removeListener method

  1. @override
void removeListener(
  1. VoidCallback listener
)
override

Remove a previously registered closure from the list of closures that are notified when the object changes.

If the given listener is not registered, the call is ignored.

This method returns immediately if dispose has been called.

If a listener is added twice, and is removed once during an iteration (e.g. in response to a notification), it will still be called again. If, on the other hand, it is removed as many times as it was registered, then it will no longer be called. This odd behavior is the result of the ChangeNotifier not being able to determine which listener is being removed, since they are identical, therefore it will conservatively still call all the listeners when it knows that any are still registered.

This surprising behavior can be unexpectedly observed when registering a listener on two separate objects which are both forwarding all registrations to a common upstream object.

See also:

  • addListener, which registers a closure to be called when the object changes.

Implementation

@override
void removeListener(VoidCallback listener) {
  // This method is allowed to be called on disposed instances for usability
  // reasons. Due to how our frame scheduling logic between render objects and
  // overlays, it is common that the owner of this instance would be disposed a
  // frame earlier than the listeners. Allowing calls to this method after it
  // is disposed makes it easier for listeners to properly clean up.
  for (int i = 0; i < _count; i++) {
    final VoidCallback? listenerAtIndex = _listeners[i];
    if (listenerAtIndex == listener) {
      if (_notificationCallStackDepth > 0) {
        // We don't resize the list during notifyListeners iterations
        // but we set to null, the listeners we want to remove. We will
        // effectively resize the list at the end of all notifyListeners
        // iterations.
        _listeners[i] = null;
        _reentrantlyRemovedListeners++;
      } else {
        // When we are outside the notifyListeners iterations we can
        // effectively shrink the list.
        _removeAt(i);
      }
      break;
    }
  }
}