runBatch<T> method
T
runBatch<T>(
- T body()
Runs body with structural notifications coalesced into a single
notifyListeners call fired after body returns.
Any number of mutations inside body — insertRoot, insert,
remove, expand, collapse, updateNode, moveNode, etc. — fire
at most one structural notification when the outermost runBatch
exits. Nested runBatch calls coalesce into the outermost one.
Animation tick notifications (addAnimationListener) are not affected and continue to fire in real time.
The notification fires even if body throws, so listeners always see
the post-batch state. Exceptions propagate after the notification.
Implementation
T runBatch<T>(T Function() body) {
_batchDepth++;
try {
return body();
} finally {
_batchDepth--;
if (_batchDepth == 0) {
// Flush any deferred visible-order rebuild BEFORE notifications
// fire — listeners reading visibleNodes/orderNidsView in their
// callback must see the post-batch state. Cheap when no
// mutation flagged dirtiness (single bool check).
_ensureVisibleOrder();
final didStructural = _batchDidRequestStructural;
final dirtyData = _batchDirtyDataNodes;
final structuralAffected = _batchAffectedStructuralUnknown
? null
: _batchAffectedStructuralKeys;
_batchDidRequestStructural = false;
_batchDirtyDataNodes = null;
_batchAffectedStructuralKeys = null;
_batchAffectedStructuralUnknown = false;
// Fire structural first: a structural notify causes the element to
// mark itself for a full refresh, which subsumes any data-only
// refresh for the same keys. Firing data first would queue a
// targeted refresh that the full refresh then redundantly repeats.
if (didStructural) {
_fireStructuralListeners(structuralAffected);
notifyListeners();
}
if (dirtyData != null && dirtyData.isNotEmpty) {
for (final key in dirtyData) {
_fireNodeDataListeners(key);
}
}
}
}
}