目录
5._reentrantlyRemovedListeners
bool _debugCreationDispatched = false;
前言
上一篇博客介绍了ChangeNotifier的用法,这篇主要介绍ChangeNotifier的实现原理。
那么,ChangeNotifier 是如何工作的?它内部又是如何维护监听器并发送通知的?本文将从源码角度出发,一步一步带你深入理解 ChangeNotifier 的实现原理。
一、ChangeNotifier定义
1.ChangeNotifier定义
ChangeNotifier 是一个混入类(mixin class),实现了 Listenable 接口,同时实现了Listenable定义的方法,具备添加、移除监听器的能力。
mixin class ChangeNotifier implements Listenable
它主要用于在数据发生变化时通知监听者(Listener),从而驱动 UI 更新。
2.Listenable的定义
我们看一下Listenable的定义,它是一个抽象类,定义了如下的方法:
以下是你提供的 Listenable 抽象类中所有注释的中文翻译版本:
abstract class Listenable {
/// 抽象的 const 构造函数。这个构造函数使得子类可以提供 const 构造函数,
/// 以便它们可以在 const 表达式中使用。
const Listenable();
/// 返回一个 [Listenable],当给定的任意一个 [Listenable]
/// 触发时都会触发该对象。
///
/// 一旦调用了该工厂方法,不得再向可迭代对象中添加或移除项。
/// 否则将导致内存泄漏或异常。
///
/// 可迭代对象中可能包含 null,这些值会被忽略。
factory Listenable.merge(Iterable<Listenable?> listenables) = _MergingListenable;
/// 注册一个回调函数,当对象通知其监听者时会调用该回调。
void addListener(VoidCallback listener);
/// 从通知对象的回调列表中移除一个先前注册的回调函数。
void removeListener(VoidCallback listener);
}
其中_MergingListenable类的定义如下,它使用一个数组_children保存Litenable类型的数组,当我们调用addListener方法的时候,把Listenable对象加入到数组中,当我们调用removeListener方法的时候,遍历数组移除指定的Listenable。 除此之外,还提供了一个toString方法,用来调试。
class _MergingListenable extends Listenable {
_MergingListenable(this._children);
final Iterable<Listenable?> _children;
@override
void addListener(VoidCallback listener) {
for (final Listenable? child in _children) {
child?.addListener(listener);
}
}
@override
void removeListener(VoidCallback listener) {
for (final Listenable? child in _children) {
child?.removeListener(listener);
}
}
@override
String toString() {
return 'Listenable.merge([${_children.join(", ")}])';
}
}
二、继承体系
Flutter 中关于监听的接口结构如下:
Listenable
├── ValueListenable<T>
│ └── ValueNotifier<T>
└── ChangeNotifier
Listenable:最基础的接口,定义了 addListener 和 removeListener 方法。
ValueListenable<T>:扩展了 Listenable,增加了 value 属性。
ValueNotifier<T>:是一个封装了 value 的 ChangeNotifier。
ChangeNotifier:可以被继承或混入,具备增删监听器及通知监听器的功能。
三、核心方法解析
这段代码是 Flutter 中 ChangeNotifier 的核心实现之一,它实现了 Listenable 接口,并通过 mixin 的方式注入到模型类中。以下是对这份源码的详解,包括实现原理和内部机制:
1.类结构与属性分析
1.Listenable的定义
mixin class ChangeNotifier implements Listenable
使用 mixin class 是Dart 3引入的新特性,允许 mixin 具有构造函数,但此处它没有构造函数。
实现了Listenable 接口,因此需要实现 addListener、removeListener 方法。
2..核心字段
ChangeNotifier中定义了几个关键字段,用于管理监听者列表和状态:
1.属性解析
1._count
int _count = 0;
作用:记录当前注册的监听者数量。
用途:_count 表示 _listeners 列表中实际有效的监听者数量(不包括 null 占位符)。它用于快速判断是否有监听者(hasListeners)以及在添加/移除监听者时更新列表状态。
2._listeners
static final List<VoidCallback?> _emptyListeners = List<VoidCallback?>.filled(0, null);
List<VoidCallback?> _listeners = _emptyListeners;
作用:存储所有注册的监听者(VoidCallback类型,允许null)。
初始化:
_emptyListeners是一个静态的空列表(长度为 0),用作初始值。
_listeners是一个List<VoidCallback?>,允许存储null,因为在某些情况下(例如通知期间移除监听者),会临时将列表中的某些位置设置为null。
3.为什么不用const []
注释中提到,const []会创建_ImmutableList类型的对象,而_listeners在运行时需要是固定长度的_GrowableList类型(尽管代码中通过List.filled创建的是固定长度列表,但逻辑上允许动态调整大小)。
保持_listeners的运行时类型一致(_GrowableList)有助于编译器优化,提高性能。
4._notificationCallStackDepth
int _notificationCallStackDepth = 0;
作用:跟踪notifyListeners的递归调用深度。
用途:用于处理通知期间的监听者移除操作。如果在notifyListener执行期间移除监听者,ChangeNotifier会延迟列表的实际缩减,直到所有通知完成(即_notificationCallStackDepth回到 0)。
5._reentrantlyRemovedListeners
int _reentrantlyRemovedListeners = 0;
&nb