Enable ChangeNotifier clients to dispatch event of object creation in constructor. (#133060)
This commit is contained in:
parent
382ceb5707
commit
89907f6da3
@ -207,6 +207,39 @@ mixin class ChangeNotifier implements Listenable {
|
||||
@protected
|
||||
bool get hasListeners => _count > 0;
|
||||
|
||||
/// Dispatches event of object creation to [MemoryAllocations.instance].
|
||||
///
|
||||
/// If the event was already dispatched or [kFlutterMemoryAllocationsEnabled]
|
||||
/// is false, the method is noop.
|
||||
///
|
||||
/// Tools like leak_tracker use the event of object creation to help
|
||||
/// developers identify the owner of the object, for troubleshooting purposes,
|
||||
/// by taking stack trace at the moment of the event.
|
||||
///
|
||||
/// But, as [ChangeNotifier] is mixin, it does not have its own constructor. So, it
|
||||
/// communicates object creation in first `addListener`, that results
|
||||
/// in the stack trace pointing to `addListener`, not to constructor.
|
||||
///
|
||||
/// To make debugging easier, invoke [ChangeNotifier.maybeDispatchObjectCreation]
|
||||
/// in constructor of the class. It will help
|
||||
/// to identify the owner.
|
||||
///
|
||||
/// Make sure to invoke it with condition `if (kFlutterMemoryAllocationsEnabled) ...`
|
||||
/// so that the method is tree-shaken away when the flag is false.
|
||||
@protected
|
||||
void maybeDispatchObjectCreation() {
|
||||
// Tree shaker does not include this method and the class MemoryAllocations
|
||||
// if kFlutterMemoryAllocationsEnabled is false.
|
||||
if (kFlutterMemoryAllocationsEnabled && !_creationDispatched) {
|
||||
MemoryAllocations.instance.dispatchObjectCreated(
|
||||
library: _flutterFoundationLibrary,
|
||||
className: '$ChangeNotifier',
|
||||
object: this,
|
||||
);
|
||||
_creationDispatched = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a closure to be called when the object changes.
|
||||
///
|
||||
/// If the given closure is already registered, an additional instance is
|
||||
@ -236,14 +269,11 @@ mixin class ChangeNotifier implements Listenable {
|
||||
@override
|
||||
void addListener(VoidCallback listener) {
|
||||
assert(ChangeNotifier.debugAssertNotDisposed(this));
|
||||
if (kFlutterMemoryAllocationsEnabled && !_creationDispatched) {
|
||||
MemoryAllocations.instance.dispatchObjectCreated(
|
||||
library: _flutterFoundationLibrary,
|
||||
className: '$ChangeNotifier',
|
||||
object: this,
|
||||
);
|
||||
_creationDispatched = true;
|
||||
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
maybeDispatchObjectCreation();
|
||||
}
|
||||
|
||||
if (_count == _listeners.length) {
|
||||
if (_count == 0) {
|
||||
_listeners = List<VoidCallback?>.filled(1, null);
|
||||
@ -505,13 +535,8 @@ class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {
|
||||
/// Creates a [ChangeNotifier] that wraps this value.
|
||||
ValueNotifier(this._value) {
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
MemoryAllocations.instance.dispatchObjectCreated(
|
||||
library: _flutterFoundationLibrary,
|
||||
className: '$ValueNotifier',
|
||||
object: this,
|
||||
);
|
||||
maybeDispatchObjectCreation();
|
||||
}
|
||||
_creationDispatched = true;
|
||||
}
|
||||
|
||||
/// The current value stored in this notifier.
|
||||
|
@ -1196,6 +1196,13 @@ class ShortcutRegistryEntry {
|
||||
/// widgets that are not descendants of the registry can listen to it (e.g. in
|
||||
/// overlays).
|
||||
class ShortcutRegistry with ChangeNotifier {
|
||||
/// Creates an instance of [ShortcutRegistry].
|
||||
ShortcutRegistry() {
|
||||
if (kFlutterMemoryAllocationsEnabled) {
|
||||
maybeDispatchObjectCreation();
|
||||
}
|
||||
}
|
||||
|
||||
bool _notificationScheduled = false;
|
||||
bool _disposed = false;
|
||||
|
||||
|
@ -482,4 +482,8 @@ class _DefaultSnapshotPainter implements SnapshotPainter {
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant _DefaultSnapshotPainter oldPainter) => false;
|
||||
|
||||
@override
|
||||
@protected
|
||||
void maybeDispatchObjectCreation() { }
|
||||
}
|
||||
|
@ -1852,6 +1852,22 @@ void main() {
|
||||
}, throwsAssertionError);
|
||||
token.dispose();
|
||||
});
|
||||
|
||||
testWidgets('dispatches object creation in constructor', (WidgetTester tester) async {
|
||||
final MemoryAllocations ma = MemoryAllocations.instance;
|
||||
assert(!ma.hasListeners);
|
||||
int eventCount = 0;
|
||||
void listener(ObjectEvent event) => eventCount++;
|
||||
ma.addListener(listener);
|
||||
|
||||
final ShortcutRegistry registry = ShortcutRegistry();
|
||||
|
||||
expect(eventCount, 1);
|
||||
|
||||
registry.dispose();
|
||||
ma.removeListener(listener);
|
||||
assert(!ma.hasListeners);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user