这是一篇Provider的源码分析。我们从一个简单的例子开始分析,看provider怎么实现的状态管理。话不多说进入主题吧。
代码语言:javascript复制class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count ;
notifyListeners();
}
}
首先我们创建自己的继承于ChangeNotifier的状态类Counter,ChangeNotifier实现Listenable的方法。监听者通过addListener注册监听,当我们调用notifyListeners会触发监听者的方法回调。
接着我们创建ChangeNotifierProvider,实现对Counter状态监听。
代码语言:javascript复制ChangeNotifierProvider(
create: (context) => Counter(),
builder: (context, child) {
return Consumer<Counter>(
builder: (context, counter, child) {
return Text('${counter.count}');
},
);
},
)
ChangeNotifierProvider继承自ListenableProvider,有两个构造方法,一个是默认的构造方法,一个是.value构造方法。通过create创作的会传递静态_dispose方法即自动管理create和dispose。.value传递一个已有的ChangeNotifier对象。的需要自己管理ChangeNotifierProvider的释放。(ps: 这里也是很多同学遇到value构造的ChangeNotifier不会随生命周期调用dispose问题)
代码语言:javascript复制class ChangeNotifierProvider<T extends ChangeNotifier?>
extends ListenableProvider<T> {
ChangeNotifierProvider({
Key? key,
required Create<T> create,
bool? lazy,
TransitionBuilder? builder,
Widget? child,
}) : super(
key: key,
create: create,
dispose: _dispose,
lazy: lazy,
builder: builder,
child: child,
);
/// Provides an existing [ChangeNotifier].
ChangeNotifierProvider.value({
Key? key,
required T value,
TransitionBuilder? builder,
Widget? child,
}) : super.value(
key: key,
builder: builder,
value: value,
child: child,
);
static void _dispose(BuildContext context, ChangeNotifier? notifier) {
notifier?.dispose();
}
}
接着往上走 ListenableProvider 继承自InheritedProvider,这里同样是一个create和value的构造方法,向父类传递一个开始监听的方法_startListening。_startListening实际就是ChangeNotifier监听刷新的实现,我们记住这个方法,后面会用到。
代码语言:javascript复制class ListenableProvider<T extends Listenable?> extends InheritedProvider<T> {
ListenableProvider({
Key? key,
required Create<T> create,
Dispose<T>? dispose,
bool? lazy,
TransitionBuilder? builder,
Widget? child,
}) : super(
key: key,
startListening: _startListening,
create: create,
dispose: dispose,
lazy: lazy,
builder: builder,
child: child,
);
/// Provides an existing [Listenable].
ListenableProvider.value({
Key? key,
required T value,
UpdateShouldNotify<T>? updateShouldNotify,
TransitionBuilder? builder,
Widget? child,
}) : super.value(
key: key,
builder: builder,
value: value,
updateShouldNotify: updateShouldNotify,
startListening: _startListening,
child: child,
);
static VoidCallback _startListening(
InheritedContext e,
Listenable? value,
) {
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
}
接着往上走 InheritedProvider 继承自SingleChildStatelessWidget,SingleChildStatelessWidget是Provider为了方便编码而导入的库,可以简化开发。可以见库介绍。我们在这里关注buildWithChild方法即可。
InheritedProvider同样有create和value的构造方法。在构造方法创建不同的_Delegate。_Delegate<T>是类似与Stateful Widget的一个类,createState可以创建对应的state对象。这里有两种类型的Delegate,_CreateInheritedProvider和_ValueInheritedProvider对应create和value的构造方法。在这里我们关注_CreateInheritedProvider的实现。创建_CreateInheritedProvider的_Delegate会传递create,startListening, dispose等方法。接下来就是实现Provider共享数据的关键,也就是InheriedWidget出场的时候啦。buildWithChild创建了_InheritedProviderScope并且将InheritedProvider作为owner参数传递过去。我们切换看下_InheritedProviderScope实现。
代码语言:javascript复制// 代码有部分省略
class InheritedProvider<T> extends SingleChildStatelessWidget {
InheritedProvider({
Key? key,
Create<T>? create,
T Function(BuildContext context, T? value)? update,
UpdateShouldNotify<T>? updateShouldNotify,
void Function(T value)? debugCheckInvalidValueType,
StartListening<T>? startListening,
Dispose<T>? dispose,
this.builder,
bool? lazy,
Widget? child,
}) : _lazy = lazy,
_delegate = _CreateInheritedProvider(
create: create,
update: update,
updateShouldNotify: updateShouldNotify,
debugCheckInvalidValueType: debugCheckInvalidValueType,
startListening: startListening,
dispose: dispose,
),
super(key: key, child: child);
/// Expose to its descendants an existing value,
InheritedProvider.value({
Key? key,
required T value,
UpdateShouldNotify<T>? updateShouldNotify,
StartListening<T>? startListening,
bool? lazy,
this.builder,
Widget? child,
}) : _lazy = lazy,
_delegate = _ValueInheritedProvider(
value: value,
updateShouldNotify: updateShouldNotify,
startListening: startListening,
),
super(key: key, child: child);
final _Delegate<T> _delegate;
final bool? _lazy;
@override
Widget buildWithChild(BuildContext context, Widget? child) {
return _InheritedProviderScope<T?>(
owner: this,
// ignore: no_runtimetype_tostring
debugType: kDebugMode ? '$runtimeType' : '',
child: builder != null
? Builder(
builder: (context) => builder!(context, child),
)
: child!,
);
}
}
_InheritedProviderScope是一个InheritedWidget,将上面传递过来的InheritedProvider(owner)对象作为我们的inherited对象。我们知道updateShouldNotify是控制InheritedWidget是否刷新的。这里updateShouldNotify always return false是因为_InheritedProviderScope重写了InheritedWidget的createElement。由element自行管理notifyClients.
代码语言:javascript复制class _InheritedProviderScope<T> extends InheritedWidget {
const _InheritedProviderScope({
required this.owner,
required this.debugType,
required Widget child,
}) : assert(null is T),
super(child: child);
final InheritedProvider<T> owner;
final String debugType;
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
return false;
}
@override
_InheritedProviderScopeElement<T> createElement() {
return _InheritedProviderScopeElement<T>(this);
}
}
_InheritedProviderScopeElement继承自InheritedElement,在performRebuild中,我们初始化了_delegateState并传递element给_Delegate。用于将InheritedElement标记脏。在下一帧build方法调用notifyClients(widget)通知刷新。
代码语言:javascript复制// 代码有部分省略
class _InheritedProviderScopeElement<T> extends InheritedElement
implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
static int _nextProviderId = 0;
bool _shouldNotifyDependents = false;
bool _debugInheritLocked = false;
bool _isNotifyDependentsEnabled = true;
bool _firstBuild = true;
bool _updatedShouldNotify = false;
bool _isBuildFromExternalSources = false;
late _DelegateState<T, _Delegate<T>> _delegateState;
late String _debugId;
@override
void performRebuild() {
if (_firstBuild) {
_firstBuild = false;
_delegateState = widget.owner._delegate.createState()..element = this;
}
super.performRebuild();
}
@override
Widget build() {
if (widget.owner._lazy == false) {
value; // this will force the value to be computed.
}
_delegateState.build(
isBuildFromExternalSources: _isBuildFromExternalSources,
);
_isBuildFromExternalSources = false;
if (_shouldNotifyDependents) {
_shouldNotifyDependents = false;
notifyClients(widget);
}
return super.build();
}
@override
void markNeedsNotifyDependents() {
if (!_isNotifyDependentsEnabled) {
return;
}
markNeedsBuild();
_shouldNotifyDependents = true;
}
@override
void unmount() {
_delegateState.dispose();
...
}
@override
T get value => _delegateState.value;
}
在_Delegate _CreateInheritedProviderState中value为Counter状态类,当获取value时会判断是否初始化,调用我们上面传入的create初始化状态类。还记得我们上面不断传递的startListening吗?也是在获取value这里创建了对Counter(ChangeNotifier)的监听。_removeListener ??= delegate.startListening?.call(element!, _value as T)
代码语言:javascript复制// 代码有部分省略
class _CreateInheritedProviderState<T>
extends _DelegateState<T, _CreateInheritedProvider<T>> {
VoidCallback? _removeListener;
bool _didInitValue = false;
T? _value;
_CreateInheritedProvider<T>? _previousWidget;
FlutterErrorDetails? _initError;
@override
T get value {
...
if (!_didInitValue) {
_didInitValue = true;
if (delegate.create != null) {
...
_value = delegate.create!(element!);
...
}
...
}
element!._isNotifyDependentsEnabled = false;
_removeListener ??= delegate.startListening?.call(element!, _value as T);
element!._isNotifyDependentsEnabled = true;
assert(delegate.startListening == null || _removeListener != null);
return _value as T;
}
@override
void dispose() {
super.dispose();
_removeListener?.call();
if (_didInitValue) {
delegate.dispose?.call(element!, _value as T);
}
}
}
上面可知,dispose由element的unmout驱动,那Value的调用又在哪呢?没错就是上面用到的Consumer组件。Consumer实际是对Provider使用的封装。buildWithChild使用了Provider.of(context),我们看下这个实现,通过_inheritedElementOf获取到_InheritedProviderScopeElement,_InheritedProviderScopeElement的Value指向Delegate的value。listen参数用于是否监听刷新,实际就是用dependOnInheritedWidgetOfExactType将组件加入InheritedWidget的监听中。
代码语言:javascript复制// 代码有部分省略
class Provider<T> extends InheritedProvider<T> {
static T of<T>(BuildContext context, {bool listen = true}) {
...
final inheritedElement = _inheritedElementOf<T>(context);
if (listen) {
// bind context with the element
// We have to use this method instead of dependOnInheritedElement, because
// dependOnInheritedElement does not support relocating using GlobalKey
// if no provider were found previously.
context.dependOnInheritedWidgetOfExactType<_InheritedProviderScope<T?>>();
}
final value = inheritedElement?.value;
...
return value as T;
}
static _InheritedProviderScopeElement<T?>? _inheritedElementOf<T>(
BuildContext context,
) {
...
}
}
至此整个Provider的刷新链路就整理完毕啦~。简单总结一下:Provider.of(context)通过_inheritedElementOf获取到element,element.value实现了Counter状态类的初始化、监听。当Counter调用notifyListeners,会触发element的rebuild,element会notifyClients通知使用了dependOnInheritedWidgetOfExactType的context刷新。