Add a hasListeners to ChangeNotifier (#14946)
I found that some ValueListeners want to know when they should start doing work (e.g. if the value comes from polling a network resource).
This commit is contained in:
parent
b011c66653
commit
b9a7f1b915
@ -68,6 +68,27 @@ class ChangeNotifier extends Listenable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether any listeners are currently registered.
|
||||||
|
///
|
||||||
|
/// Clients should not depend on this value for their behavior, because having
|
||||||
|
/// one listener's logic change when another listener happens to start or stop
|
||||||
|
/// listening will lead to extremely hard-to-track bugs. Subclasses might use
|
||||||
|
/// this information to determine whether to do any work when there are no
|
||||||
|
/// listeners, however; for example, resuming a [Stream] when a listener is
|
||||||
|
/// added and pausing it when a listener is removed.
|
||||||
|
///
|
||||||
|
/// Typically this is used by overriding [addListener], checking if
|
||||||
|
/// [hasListeners] is false before calling `super.addListener()`, and if so,
|
||||||
|
/// starting whatever work is needed to determine when to call
|
||||||
|
/// [notifyListeners]; and similarly, by overriding [removeListener], checking
|
||||||
|
/// if [hasListeners] is false after calling `super.removeListener()`, and if
|
||||||
|
/// so, stopping that same work.
|
||||||
|
@protected
|
||||||
|
bool get hasListeners {
|
||||||
|
assert(_debugAssertNotDisposed());
|
||||||
|
return _listeners.isNotEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
/// Register a closure to be called when the object changes.
|
/// Register a closure to be called when the object changes.
|
||||||
///
|
///
|
||||||
/// This method must not be called after [dispose] has been called.
|
/// This method must not be called after [dispose] has been called.
|
||||||
|
@ -8,14 +8,14 @@ import 'dart:collection';
|
|||||||
///
|
///
|
||||||
/// Consider using an [ObserverList] instead of a [List] when the number of
|
/// Consider using an [ObserverList] instead of a [List] when the number of
|
||||||
/// [contains] calls dominates the number of [add] and [remove] calls.
|
/// [contains] calls dominates the number of [add] and [remove] calls.
|
||||||
|
// TODO(ianh): Use DelegatingIterable, possibly moving it from the collection
|
||||||
|
// package to foundation, or to dart:collection.
|
||||||
class ObserverList<T> extends Iterable<T> {
|
class ObserverList<T> extends Iterable<T> {
|
||||||
final List<T> _list = <T>[];
|
final List<T> _list = <T>[];
|
||||||
bool _isDirty = false;
|
bool _isDirty = false;
|
||||||
HashSet<T> _set;
|
HashSet<T> _set;
|
||||||
|
|
||||||
/// Adds an item to the end of this list.
|
/// Adds an item to the end of this list.
|
||||||
///
|
|
||||||
/// The given item must not already be in the list.
|
|
||||||
void add(T item) {
|
void add(T item) {
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
_list.add(item);
|
_list.add(item);
|
||||||
@ -23,6 +23,8 @@ class ObserverList<T> extends Iterable<T> {
|
|||||||
|
|
||||||
/// Removes an item from the list.
|
/// Removes an item from the list.
|
||||||
///
|
///
|
||||||
|
/// This is O(N) in the number of items in the list.
|
||||||
|
///
|
||||||
/// Returns whether the item was present in the list.
|
/// Returns whether the item was present in the list.
|
||||||
bool remove(T item) {
|
bool remove(T item) {
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
@ -49,4 +51,10 @@ class ObserverList<T> extends Iterable<T> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Iterator<T> get iterator => _list.iterator;
|
Iterator<T> get iterator => _list.iterator;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isEmpty => _list.isEmpty;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isNotEmpty => _list.isNotEmpty;
|
||||||
}
|
}
|
||||||
|
@ -235,4 +235,32 @@ void main() {
|
|||||||
"Listenable.merge([null, Instance of 'TestNotifier'])",
|
"Listenable.merge([null, Instance of 'TestNotifier'])",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('hasListeners', () {
|
||||||
|
final HasListenersTester<bool> notifier = new HasListenersTester<bool>(true);
|
||||||
|
expect(notifier.testHasListeners, isFalse);
|
||||||
|
void test1() { }
|
||||||
|
void test2() { }
|
||||||
|
notifier.addListener(test1);
|
||||||
|
expect(notifier.testHasListeners, isTrue);
|
||||||
|
notifier.addListener(test1);
|
||||||
|
expect(notifier.testHasListeners, isTrue);
|
||||||
|
notifier.removeListener(test1);
|
||||||
|
expect(notifier.testHasListeners, isTrue);
|
||||||
|
notifier.removeListener(test1);
|
||||||
|
expect(notifier.testHasListeners, isFalse);
|
||||||
|
notifier.addListener(test1);
|
||||||
|
expect(notifier.testHasListeners, isTrue);
|
||||||
|
notifier.addListener(test2);
|
||||||
|
expect(notifier.testHasListeners, isTrue);
|
||||||
|
notifier.removeListener(test1);
|
||||||
|
expect(notifier.testHasListeners, isTrue);
|
||||||
|
notifier.removeListener(test2);
|
||||||
|
expect(notifier.testHasListeners, isFalse);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class HasListenersTester<T> extends ValueNotifier<T> {
|
||||||
|
HasListenersTester(T value) : super(value);
|
||||||
|
bool get testHasListeners => hasListeners;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user