一、简介
Provider 是用于状态管理的轻量级库,基于 InheritedWidget 和 ChangeNotifier 构建,可以帮助开发者轻松地管理应用程序的状态,并提高代码的可读性和可维护性。
二、ChangeNotifier
ChangeNotifier 主要有两个方法:addListener 注册监听,notifyListeners 触发监听回调。
class ChangeNotifier implements Listenable {
int _count = 0;
static final List<VoidCallback?> _emptyListeners = List<VoidCallback?>.filled(0, null);
List<VoidCallback?> _listeners = _emptyListeners;
/// 省略无关代码...
@override
void addListener(VoidCallback listener) {
assert(ChangeNotifier.debugAssertNotDisposed(this));
if (kFlutterMemoryAllocationsEnabled && !_creationDispatched) {
MemoryAllocations.instance.dispatchObjectCreated(
library: _flutterFoundationLibrary,
className: '$ChangeNotifier',
object: this,
);
_creationDispatched = true;
}
if (_count == _listeners.length) {
if (_count == 0) {
_listeners = List<VoidCallback?>.filled(1, null);
} else {
final List<VoidCallback?> newListeners =
List<VoidCallback?>.filled(_listeners.length * 2, null);
for (int i = 0; i < _count; i++) {
newListeners[i] = _listeners[i];
}
_listeners = newListeners;
}
}
_listeners[_count++] = listener;
}
/// 省略无关代码...
void notifyListeners() {
assert(ChangeNotifier.debugAssertNotDisposed(this));
if (_count == 0) {
return;
}
_notificationCallStackDepth++;
final int end = _count;
for (int i = 0; i < end; i++) {
try {
_listeners[i]?.call();
} catch (exception, stack) {
/// 省略无关代码...
}
}
/// 省略无关代码...
}
}
三、InheritedWidget
InheritedWidget 是跨组件获取数据的关键组件,flutter 中常用的 Theme 也是基于 InheritedWidget 实现的,下面通过 Theme 来分析 InheritedWidget 的原理。
在 flutter 中常常通过 Theme.of(context)来获取主题相关的数据,当主题数据更新时,调用 Theme.of(context)的子 widget 也会随之更新。
/// Theme.of 源码
static ThemeData of(BuildContext context) {
final _InheritedTheme? inheritedTheme = context.dependOnInheritedWidgetOfExactType<_InheritedTheme>();
final MaterialLocalizations? localizations = Localizations.of<MaterialLocalizations>(context, MaterialLocalizations);
final ScriptCategory category = localizations?.scriptCategory ?? ScriptCategory.englishLike;
final ThemeData theme = inheritedTheme?.theme.data ?? _kFallbackTheme;
return ThemeData.localize(theme, theme.typography.geometryThemeFor(category));
}
可以看到 Theme.of 调用了"context.dependOnInheritedWidgetOfExactType"这个方法获取 inheritedTheme,再调用 inheritedTheme.theme.data 拿到了数据。
tip: context 就是 element 的封装
/// dependOnInheritedWidgetOfExactType源码
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>(
{Object? aspect}) {
assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement? ancestor =
_inheritedWidgets == null ? null : _inheritedWidgets![T];
if (ancestor != null) {
return dependOnInheritedElement(ancestor, aspect: aspect) as T;
}
_hadUnsatisfiedDependencies = true;
return null;
}
/// dependOnInheritedElement 源码
InheritedWidget dependOnInheritedElement(InheritedElement ancestor,
{Object? aspect}) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies!.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget as InheritedWidget;
}
-
dependOnInheritedWidgetOfExactType 从子 element 的_inheritedWidgets 中获取到 InheritedElement,key 为_InheritedTheme 的 runtimeType,接下来调用 dependOnInheritedElement 并返回对应的 InheritedWidget。
-
dependOnInheritedElement 作用是建立 InheritedElement 和当前 element 的依赖关系,后面介绍 Provider 源码时会详细介绍,这里先关注数据是如何跨组件传递的。
-
可以找到_inheritedWidgets 是在_updateInheritance 方法中赋值的
@override
void _updateInheritance() {
assert(_lifecycleState == _ElementLifecycle.active);
final PersistentHashMap<Type, InheritedElement> incomingWidgets =
_parent?._inheritedWidgets ?? const PersistentHashMap<Type, InheritedElement>.empty();
_inheritedWidgets = incomingWidgets.put(widget.runtimeType, this);
}
_updateInheritance 在 element 创建时调用,子 element 的_inheritedWidgets 来自父 element 的_inheritedWidgets。再来看_InheritedTheme 的祖父类 InheritedElement。
class InheritedElement extends ProxyElement {
InheritedElement(InheritedWidget super.widget);
final Map<Element, Object?> _dependents = HashMap<Element, Object?>();
@override
void _updateInheritance() {
assert(_lifecycleState == _ElementLifecycle.active);
final PersistentHashMap<Type, InheritedElement> incomingWidgets =
_parent?._inheritedWidgets ?? const PersistentHashMap<Type, InheritedElement>.empty();
_inheritedWidgets = incomingWidgets.put(widget.runtimeType, this);
}
/// 省略无关代码...
}
- InheritedElement 重写_updateInheritance 把自身的 element 的引用存入_inheritedWidgets 中。
- 后代 element 的__inheritedWidgets 来自父类,这样就能存有祖先 InheritedElement 的引用,通过 InheritedWidget.runtimeType 就能获取 InheritedElement,再通过 InheritedElement.widget.data 就可以拿到保存在 InheritedWidget 中的数据。
四、InheritedWidget 小结
- InheritedElement 重写_updateInheritance 方法将自身引用存入_inheritedWidgets 中,key 为 InheritedWidget 的 runTimeType。
- 后代 element 的_inheritedWidgets 来自父 element 的_inheritedWidgets,那么在后代 element 的_inheritedWidgets 中就会存有祖先 InheritedElement 的引用。
- 子 widget 调用 context.dependOnInheritedWidgetOfExactType 方法,传入需要查找的 InheritedWidget runTimeType,从子 element 的_inheritedWidgets 拿到对应类型的最近祖先 InheritedElement。
- 调用 InheritedElement.widget.value 拿到 InheritedWidget 中的数据。
五、Provider 源码分析
1、ChangeNotifierProvider 源码
/// ChangeNotifierProvider源码
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();
}
}
ChangeNotifierProvider 继承 ListenableProvider ,有两种构造函数,一个是传入数据的 create 方法,一个是直接传入数据 value。value 的类型或者 create 方法的返回值类型是继承 ChangeNotifier 的类 T。
ChangeNotifierProvider 的两种构造方法差别不大,因为篇幅原因,后续源码中只会展示直接传入 value 的构造方法
class ListenableProvider<T extends Listenable?> extends InheritedProvider<T> {
/// 省略ListenableProvider构造函数...
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);
}
}
ListenableProvider 继承 InheritedProvider,ListenableProvider 中有个重要的方法_startListening,后面我们可以看到它调用的地方。
class InheritedProvider<T> extends SingleChildStatelessWidget {
/// 省略InheritedProvider构造函数代码...
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);
/// 省略部分无关代码...
@override
_InheritedProviderElement<T> createElement() {
return _InheritedProviderElement<T>(this);
}
@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!,
);
}
}
InheritedProvider 是一个 widget,持有代理类_delegate,在 buildWithChild 中返回了_InheritedProviderScope,并将 this 作为_InheritedProviderScope 的 owner 属性传入。
class _InheritedProviderScope<T> extends InheritedWidget {
/// 省略部分无关代码
@override
_InheritedProviderScopeElement<T> createElement() {
return _InheritedProviderScopeElement<T>(this);
}
}
/// _InheritedProviderScopeElement源码
class _InheritedProviderScopeElement<T> extends InheritedElement
implements InheritedContext<T> {
/// 省略部分无关代码
late final _DelegateState<T, _Delegate<T>> _delegateState =
widget.owner._delegate.createState()..element = this;
late String _debugId;
/// 省略部分无关代码...
@override
void updateDependencies(Element dependent, Object? aspect) {
final dependencies = getDependencies(dependent);
// once subscribed to everything once, it always stays subscribed to everything
if (dependencies != null && dependencies is! _Dependency<T>) {
return;
}
if (aspect is _SelectorAspect<T>) {
final selectorDependency =
(dependencies ?? _Dependency<T>()) as _Dependency<T>;
if (selectorDependency.shouldClearSelectors) {
selectorDependency.shouldClearSelectors = false;
selectorDependency.selectors.clear();
}
if (selectorDependency.shouldClearMutationScheduled == false) {
selectorDependency.shouldClearMutationScheduled = true;
Future.microtask(() {
selectorDependency
..shouldClearMutationScheduled = false
..shouldClearSelectors = true;
});
}
selectorDependency.selectors.add(aspect);
setDependencies(dependent, selectorDependency);
} else {
// subscribes to everything
setDependencies(dependent, const Object());
}
}
@override
void notifyDependent(InheritedWidget oldWidget, Element dependent) {
final dependencies = getDependencies(dependent);
if (kDebugMode) {
ProviderBinding.debugInstance.providerDidChange(_debugId);
}
var shouldNotify = false;
if (dependencies != null) {
if (dependencies is _Dependency<T>) {
if (dependent.dirty) {
return;
}
for (final updateShouldNotify in dependencies.selectors) {
try {
assert(() {
_debugIsSelecting = true;
return true;
}());
shouldNotify = updateShouldNotify(value);
} finally {
assert(() {
_debugIsSelecting = false;
return true;
}());
}
if (shouldNotify) {
break;
}
}
} else {
shouldNotify = true;
}
}
if (shouldNotify) {
dependent.didChangeDependencies();
}
}
/// 省略部分无关代码...
@override
void markNeedsNotifyDependents() {
if (!_isNotifyDependentsEnabled) {
return;
}
markNeedsBuild();
_shouldNotifyDependents = true;
}
/// 省略部分无关代码...
@override
T get value => _delegateState.value;
@override
InheritedWidget dependOnInheritedElement(
InheritedElement ancestor, {
Object? aspect,
}) {
/// 省略部分无关代码...
return super.dependOnInheritedElement(ancestor, aspect: aspect);
}
/// 省略部分无关代码...
}
InheritedProviderScopeElement 中有很多关键的逻辑,接下来结合 Provider 最常用的两个使用 context.read 和 content.select 的源码来分析 InheritedProviderScopeElement 实现了哪些关键逻辑。
context.read 仅获取数据不监听数据改变
context.select 获取数据同时监听数据改变刷新 widget
2、context.read 源码分析
/// context.read源码
T read<T>() {
return Provider.of<T>(this, listen: false);
}
/// Provider.of源码
static T of<T>(BuildContext context, {bool listen = true}) {
final inheritedElement = _inheritedElementOf<T>(context);
if (listen) {
context.dependOnInheritedWidgetOfExactType<_InheritedProviderScope<T?>>();
}
final value = inheritedElement?.value;
if (_isSoundMode) {
if (value is! T) {
throw ProviderNullException(T, context.widget.runtimeType);
}
return value;
}
return value as T;
}
context.read 调用 Provider.of, listen 传 false,Provider.of 中调用_inheritedElementOf 获取 inheritedElement,再调用 inheritedElement.value 获得数据。
/// _inheritedElementOf源码
static _InheritedProviderScopeElement<T?>? _inheritedElementOf<T>(
BuildContext context,
) {
/// 忽略无关代码...
final inheritedElement = context.getElementForInheritedWidgetOfExactType<
_InheritedProviderScope<T?>>() as _InheritedProviderScopeElement<T?>?;
if (inheritedElement == null && null is! T) {
throw ProviderNotFoundException(T, context.widget.runtimeType);
}
return inheritedElement;
}
/// getElementForInheritedWidgetOfExactType 源码
@override
InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T];
return ancestor;
}
在_inheritedElementOf 方法中调用了 getElementForInheritedWidgetOfExactType 方法,这个和前面介绍的 dependOnInheritedWidgetOfExactType 都是从_inheritedWidgets 中获取 InheritedElement,只是少了调用了 dependOnInheritedElement 方法。
/// inheritedElement?.value
@override
T get value => _delegateState.value;
/// _delegateState的创建
late final _DelegateState<T, _Delegate<T>> _delegateState =
widget.owner._delegate.createState()..element = this;
获取 inheritedElement 后,调用了_InheritedProviderScopeElement 的 get value 方法,_delegateState 由 owner._delegate.createState 创建。接着来看_delegate 的 createState 方法
_delegate = _ValueInheritedProvider(
value: value,
updateShouldNotify: updateShouldNotify,
startListening: startListening,
),
_delegate = _CreateInheritedProvider(
create: create,
update: update,
updateShouldNotify: updateShouldNotify,
debugCheckInvalidValueType: debugCheckInvalidValueType,
startListening: startListening,
dispose: dispose,
)
InheritedProvider 两种构造方法,_delegate 有两种对应的实现方式,两种主要逻辑差别不大,下面我们主要看_ValueInheritedProvider。
class _ValueInheritedProvider<T> extends _Delegate<T> {
/// 省略无关代码...
final T value;
/// 省略无关代码...
@override
_ValueInheritedProviderState<T> createState() {
return _ValueInheritedProviderState<T>();
}
}
class _ValueInheritedProviderState<T>
extends _DelegateState<T, _ValueInheritedProvider<T>> {
VoidCallback? _removeListener;
@override
T get value {
element!._isNotifyDependentsEnabled = false;
_removeListener ??= delegate.startListening?.call(element!, delegate.value);
element!._isNotifyDependentsEnabled = true;
assert(delegate.startListening == null || _removeListener != null);
return delegate.value;
}
/// 省略无关代码...
}
- 在_ValueInheritedProviderState 中,我们看到了 inheritedElement?.value 最终调用的方法 get value。
- 在 get value 方法中调用了 _removeListener ??= delegate.startListening?.call(element!, _value as T);然后返回了 delegate.value。
- 结合前面的 _startListening 函数,可以知道这里将_InheritedProviderScopeElement 的 markNeedsNotifyDependents 方法加入到了 value 对象的 _listeners 中,当 value 对象调用 notifyListener 方法,_InheritedProviderScopeElement 的 markNeedsNotifyDependents 方法就会调用。
2、context.select 源码分析
R select<T, R>(R Function(T value) selector) {
/// 省略无关代码...
final inheritedElement = Provider._inheritedElementOf<T>(this);
try {
final value = inheritedElement?.value;
/// 省略无关代码...
final selected = selector(value);
if (inheritedElement != null) {
dependOnInheritedElement(
inheritedElement,
aspect: (T? newValue) {
if (newValue is! T) {
throw ProviderNullException(T, widget.runtimeType);
}
return !const DeepCollectionEquality()
.equals(selector(newValue), selected);
},
);
} else {
dependOnInheritedWidgetOfExactType<_InheritedProviderScope<T?>>();
}
return selected;
} finally {
/// 省略无关代码...
}
}ß
在 select 中同样调用了_inheritedElementOf 和 inheritedElement?.value 来获取数据,不一样的 select 多了一步:调用 dependOnInheritedElement,并传入了 aspect 回调函数,aspect 的返回值是 newValue 和当前值是否相等。
//// dependOnInheritedElement源码
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies!.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget as InheritedWidget;
}
/// _InheritedProviderScopeElement updateDependencies源码
@override
void updateDependencies(Element dependent, Object? aspect) {
final dependencies = getDependencies(dependent);
// once subscribed to everything once, it always stays subscribed to everything
if (dependencies != null && dependencies is! _Dependency<T>) {
return;
}
if (aspect is _SelectorAspect<T>) {
final selectorDependency =
(dependencies ?? _Dependency<T>()) as _Dependency<T>;
if (selectorDependency.shouldClearSelectors) {
selectorDependency.shouldClearSelectors = false;
selectorDependency.selectors.clear();
}
if (selectorDependency.shouldClearMutationScheduled == false) {
selectorDependency.shouldClearMutationScheduled = true;
Future.microtask(() {
selectorDependency
..shouldClearMutationScheduled = false
..shouldClearSelectors = true;
});
}
selectorDependency.selectors.add(aspect);
setDependencies(dependent, selectorDependency);
} else {
// subscribes to everything
setDependencies(dependent, const Object());
}
}
/// setDependencies源码
@protected
void setDependencies(Element dependent, Object? value) {
_dependents[dependent] = value;
}
- dependOnInheritedElement 将 InheritedElement 的引用存入子 element 的_dependencies 中再调用 InheritedElement 的 updateDependencies 方法。
- updateDependencies 将子 element 作为 key 存入_dependents 中,value 是 selectorDependency,selectorDependency.selectors 中存入 aspect。
3、markNeedsNotifyDependents
通过前面 context.read 和 context.select 的分析,知道了当数据 model 调用 notifyListener 更新时,会调用 InheritedElement 的 markNeedsNotifyDependents 方法。 markNeedsNotifyDependents 最终会调用到 notifyDependent
@override
void notifyDependent(InheritedWidgetoldWidget, Element dependent) {
final dependencies = getDependencie(dependent);
if (kDebugMode) {
ProviderBinding.debugInstanceproviderDidChange(_debugId);
}
var shouldNotify = false;
if (dependencies != null) {
if (dependencies is _Dependency<T>) {
if (dependent.dirty) {
return;
}
for (final updateShouldNotify independencies.selectors) {
try {
assert(() {
_debugIsSelecting = true;
return true;
}());
shouldNotify = updateShouldNotif(value);
} finally {
assert(() {
_debugIsSelecting = false;
return true;
}());
}
if (shouldNotify) {
break;
}
}
} else {
shouldNotify = true;
}
}
if (shouldNotify) {
dependent.didChangeDependencies();
}
}
在 notifyDependent 中会遍历_dependencies,_dependencies 中 key 为子 element,value.selectors 中保存了比较新旧值是否相等的回调函数,如果返回值相等就不调用 didChangeDependencies 触发子 element 的更新。
因为 context.read 没有将子 element 加入到 dependencies 中,所以子 element 不会随着数据更新
markNeedsNotifyDependents 触发更新的原理就不过多介绍了,感兴趣的可以看源码和其他博客
4、总结
- ChangeNotifierProvider 的祖父类是 InheritedProvider,InheritedProvider buildWithChild 将 child widget 包裹一层_InheritedProviderScope
- _InheritedProviderScope 继承 InheritedWidget,对应的 element: _InheritedProviderScopeElement 继承 InheritedElement,InheritedElement 会将自身的引用存入_inheritedWidgets 中。子 element 继承父 element 的_inheritedWidgets,从而可以获取到_InheritedProviderScopeElement
- context.read 从子 element 的_inheritedWidgets 中获取到 InheritedProviderScopeElement,并调用 value 方法获取数据的同时,将 InheritedProviderScopeElement 的 markNeedsNotifyDependents 方法添加到 value 的监听回调中
- context.select 比 context.read 多调了 dependOnInheritedElement 方法,会将子 element 的引用作为 key,比较新旧数据的方法作为 value,存入 InheritedProviderScopeElement 的_dependents 中。
- value 数据更新后调用 notifyListener,会调用 InheritedProviderScopeElement 的 markNeedsNotifyDependents 方法,再调用 notifyDependent 方法,遍历_dependents,调用比值的回调函数,值不同就调用子 element 的 didChangeDependencies 更新子 widget。