getManagedDisposer method
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
manageAndReturnTypedDisposable.
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 = ManagedDisposer(disposer);
_internalDisposables.add(disposable);
disposable.didDispose.then((_) {
if (!_isDisposedOrDisposing) {
_logUnmanageMessage(disposer);
_internalDisposables.remove(disposable);
}
});
return disposable;
}