Provider源码分析
ChangeNotifierProvider、ChangeNotifier、Consumer的关系
一、ChangeNotifierProvider
1、ChangeNotifierProvider的父类ListenableProvider,ListenableProvider中实现了_startListening方法,_startListening主要是将Element的刷新方法添加到ChangeNotifier中的_listeners中
class ListenableProvider<T extends Listenable?> extends
ListenableProvider({
...
}) : super(
key: key,
startListening: _startListening,
...
);
static VoidCallback _startListening(
InheritedContext e,
Listenable? value, //该对象其实就是ChangeNotifier对象
) {
///添加element刷新方法
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
2、ListenableProvider将startListening传入其父类InheritedProvider,InheritedProvider主要是创建delegate = _CreateInheritedProvider。这个delegate就是_CreateInheritedProvider中delegate.startListening中的delegate
二、ChangNotifier
1、ChangNotifier负责更新UI
ChangeNotifier中notifyListeners,通过遍历_listeners,实现强制刷新UI
void notifyListeners() {
assert(_debugAssertNotDisposed());
if (_count == 0)
return;
_notificationCallStackDepth++;
final int end = _count;
for (int i = 0; i < end; i++) {
try {
_listeners[i]?.call();
} catch (exception, stack) {
...
}
三、Consumer
1、Consumer:包裹待刷新UI,在buildWithChild中将Provider.of<T>(context)传入builder方法
class Consumer<T> extends SingleChildStatelessWidget
...
@override
Widget buildWithChild(BuildContext context, Widget? child) {
return builder(
context,
Provider.of<T>(context),//传入ChangeNotifier
child,
);
}
2、解析 Provider.of<T>(context)
Provider.of<T>(context)是获取ChangeNotifier对象的方法
Provider.of中通过传入的context,获取父视图为inheritedElement的对象
获取到inheritedElement,通过inheritedElement.getValue的方式获取ChangeNotifier对象
static T of<T>(BuildContext context, {bool listen = true}) {
///获取父视图为inheritedElement的对象
final inheritedElement = _inheritedElementOf<T>(context);
if (listen) {
context.dependOnInheritedWidgetOfExactType<_InheritedProviderScope<T?>>();
}
///调用inheritedElement.getValue获取Provider对象的对象
final value = inheritedElement?.value;
...
return value as T;
}
7、继续查看inheritedElement?.value。通过断点可以进入_CreateInheritedProvider 类中get Value方法。调用startListening将当前Consumer包裹的element添加到Prorivder的_listeners数组中
class _CreateInheritedProvider<T> extends _Delegate<T> {
...
@override
T get value {
...
element!._isNotifyDependentsEnabled = false;
///调用startListening将当前Consumer包裹的element添加到ChangeNotifier的_listeners数组中
_removeListener ??= delegate.startListening?.call(element!, _value as T);
element!._isNotifyDependentsEnabled = true;
assert(delegate.startListening == null || _removeListener != null);
return _value as T;
}
四、总结
通过调用notifyListeners()来刷新所有Consumer完整的Provider执行流程大概就是这样,流程图如下