Unverified Commit b9a7f1b9 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

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).
parent b011c666
......@@ -68,6 +68,27 @@ class ChangeNotifier extends Listenable {
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.
///
/// 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
/// [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> {
final List<T> _list = <T>[];
bool _isDirty = false;
HashSet<T> _set;
/// Adds an item to the end of this list.
///
/// The given item must not already be in the list.
void add(T item) {
_isDirty = true;
_list.add(item);
......@@ -23,6 +23,8 @@ class ObserverList<T> extends Iterable<T> {
/// 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.
bool remove(T item) {
_isDirty = true;
......@@ -49,4 +51,10 @@ class ObserverList<T> extends Iterable<T> {
@override
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'])",
);
});
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment