deleteRouteDependency method
Deletes the dependency registered under key on behalf of a disposed
route, keeping it alive when still-mounted widgets depend on it.
Meant for internal usage of the RouterReportManager: when a route is
disposed, the instances linked to it are deleted. An instance that
still has widget subscribers (GetBuilder/GetX listeners) at that
moment may be shared with widgets of another, still-visible route —
e.g. a controller created during a rebuild of a lower route's subtree
while the disposed route was topmost — so its deletion is deferred to
the end of the frame, after the disposed route's own subtree has
unmounted and released its subscriptions:
- if no subscriber remains, the instance is deleted normally;
- if subscribers remain, they belong to still-mounted widgets of other routes and the instance is kept alive (it is disposed later by its creator widget's unmount or an explicit delete).
A registration superseded while the route was disposing (pending
lateRemove chain) is peeled synchronously, exactly like delete.
Implementation
void deleteRouteDependency(String key) {
final dep = _singletons[key];
if (dep == null) {
Get.log('Instance "$key" already removed.', isError: true);
return;
}
final live = dep.dependency;
final hasSubscribers =
live is ListNotifierSingleMixin &&
!live.isDisposed &&
live.listenersLength > 0;
if (dep.lateRemove != null || !hasSubscribers) {
delete(key: key);
return;
}
WidgetsBinding.instance.addPostFrameCallback((_) {
final current = _singletons[key];
if (current == null) return;
if (!identical(current, dep)) {
// The registration was superseded meanwhile (e.g. the same key was
// re-registered for a fresh route while this route was disposing).
// If the stale factory is pending in the lateRemove chain, peel it
// like the synchronous path would have; a fresh unrelated
// registration must not be touched.
var chain = current.lateRemove;
while (chain != null) {
if (identical(chain, dep)) {
delete(key: key);
return;
}
chain = chain.lateRemove;
}
return;
}
if (!live.isDisposed && live.listenersLength > 0) {
// The disposed route marked the key dirty on its way out; the
// instance is consciously kept alive for its remaining
// subscribers, so it must not be treated as stale by future
// registrations.
dep.isDirty = false;
Get.log(
'Instance "$key" was kept alive on route disposal: '
'widgets are still subscribed to it.',
);
return;
}
delete(key: key);
});
}