getManagedDisposer method

  1. @mustCallSuper
  2. @override
ManagedDisposer getManagedDisposer (Disposer disposer)
@mustCallSuper, override

Automatically handle arbitrary disposals using a callback.

The passed Disposer will be called on disposal of the parent object (the parent object is MyDisposable in the example below). A ManagedDisposer is returned in case the Disposer should be invoked and cleaned up before disposal of the parent object.

 class MyDisposable extends Disposable {
   void makeRequest() {
     var request = new Request();

     // This will ensure that cancel is called if MyDisposable is
     // disposed.
     var disposable = getManagedDisposer(request.cancel);

     // Evict request if it has not completed within a given time
     // frame. All internal references will be cleaned up.
     getManagedTimer(new Duration(minutes: 2), disposable.dispose);

     // ...
   }
 }

Note: Disposable will store a reference to disposer until an explicit dispose call to either the parent object, or the returned ManagedDisposer. The reference to disposer will prevent the callback and anything referenced in the callback from being garbage collected until one of these two things happen. These references can be a vector for memory leaks. For this reason it is recommended to avoid references in disposer to objects not created by the parent object. These objects should be managed by their parent. At most one would need to manage the parent using manageDisposable.

Example BAD use case: request should not be referenced in a Disposer because MyDisposable did not create it.

 class MyDisposable extends Disposable {
   void addRequest(Request request) {
     // ...

     // request comes from an external source, the reference held by
     // this closure may introduce a memory leak.
     getManagedDisposer(request.cancel);
   }
 }

The parameter may not be null.

Implementation

@mustCallSuper
@override
ManagedDisposer getManagedDisposer(Disposer disposer) {
  _throwOnInvalidCall('getManagedDisposer', 'disposer', disposer);
  _logManageMessage(disposer);

  var disposable = new ManagedDisposer(disposer);

  _internalDisposables.add(disposable);

  disposable.didDispose.then((_) {
    // ignore: deprecated_member_use
    if (!isDisposedOrDisposing) {
      _logUnmanageMessage(disposer);
      _internalDisposables.remove(disposable);
    }
  });

  return disposable;
}