[TOC]
Provider围绕InheritedWidget开发的管理state的Widget,实现父节点存储数据,子节点访问数据的功能。结合ChangeNotifer和InheritedWidget两个组件的功能,ChangeNotifer实现数据改变发出通知,InheritedWidget实现接收通知,并build dependant的功能。
对外暴露了一些组件:
- MultiProvider
- Provider 通过Create、Dispose两个回调管理数据的生命周期
- ChangeNotifierProvider
- FutureProvider
- ProxyProvider
- Consumer
- Selector
带provider的类是数据的生产方,根据不同的目的有多种数据生产方式;Consumer、Selector是数据消费者。
ChangeNotifierProvider
Listens to a ChangeNotifier, expose it to its descendants and rebuilds dependents whenever ChangeNotifier.notifyListeners is called.
- 管理ChangeNotifier, 监听ChangeNotifier的变化
- 将ChangeNotifier 暴露给descendants
- 当ChangeNotifier.notifyListeners被调用,rebuild dependents。
定义
class ChangeNotifierProvider<T extends ChangeNotifier?>
extends ListenableProvider<T>
- 通过
T extends ChangeNotifier?定义看出这个类的核心是管理ChangeNotifier - 继承于ListenableProvider
构造函数
Depending on whether you want to create or reuse a ChangeNotifier, you will want to use different constructors.
- 创建型
- 重用型
To create a value, use the default constructor.
Creating the instance inside build using ChangeNotifierProvider.value will lead to memory leaks and potentially undesired side-effects.
See this stackoverflow answer which explains in further details why using the .value constructor to create values is undesired.
typedef Create<T> = T Function(BuildContext context);
typedef TransitionBuilder = Widget Function(BuildContext context, Widget? child);
// 释放数据函数,入参是数据ChangeNotifier
static void _dispose(BuildContext context, ChangeNotifier? notifier) {
notifier?.dispose();
}
// 创建型【管理的数据是创建出来的】构造函数
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,
);
DO create a new ChangeNotifier inside create.
ChangeNotifierProvider(
create: (_) => new MyChangeNotifier(),
child: ...
)
DON'T use ChangeNotifierProvider.value to create your ChangeNotifier.
ChangeNotifierProvider.value(
value: new MyChangeNotifier(),
child: ...
)
DON'T create your ChangeNotifier from variables that can change over the time. In such situation, your ChangeNotifier would never be updated when the value changes.
int count;
ChangeNotifierProvider(
create: (_) => new MyChangeNotifier(count),
child: ...
)
- 创建型的就用默认构造函数
- 创建型的不要使用.value构造函数
- 创建ChangeNotifier不要传递随着时间推移可能变化的参数,否则导致数据变化是,ChangeNotifier不会被更新的问题
Reusing an existing instance of ChangeNotifier
If you already have an instance of ChangeNotifier and want to expose it, you should use ChangeNotifierProvider.value instead of the default constructor. Failing to do so may dispose the ChangeNotifier when it is still in use.
已经有数据ChangeNotifier, 使用复用型的构造函数,否则会导致数据使用的时候被释放,因为该类将dispose传递到父类了, 那么InheritedWidget释放的时候数据也要释放,这时数据还可能被其他地方使用。
DO use ChangeNotifierProvider.value to provide an existing ChangeNotifier.
MyChangeNotifier variable;
ChangeNotifierProvider.value(
value: variable,
child: ...
)
DON'T reuse an existing ChangeNotifier using the default constructor
MyChangeNotifier variable;
ChangeNotifierProvider(
create: (_) => variable,
child: ...
)
总结
ChangeNotifierProvider
数据生产、释放
create ChangeNotifier数据创建
dispose ChangeNotifier 数据释放
widget - 子节点,暴露了数据了,有子节点数据才有意义呀
builder or child
接着看父类 ListenableProvider
ListenableProvider
定义
class ListenableProvider<T extends Listenable?> extends InheritedProvider<T> {
数据变化的回调
static VoidCallback _startListening(
InheritedContext e,
Listenable? value,
) {
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
_InheritedProviderScopeElement 实现了markNeedsNotifyDependents
@override
void markNeedsNotifyDependents() {
if (!_isNotifyDependentsEnabled) {
return;
}
markNeedsBuild();
_shouldNotifyDependents = true;
}
小结
数据变化的核心逻辑:
数据变化 --> notifiylistener --> InheritedWidget build 【_InheritedProviderScopeElement】
--> 进一步触发dependant的 build
InheritedProvider
A generic implementation of an InheritedWidget. Any descendant of this widget can obtain value using Provider.of. Do not use this class directly unless you are creating a custom "Provider". Instead use Provider class, which wraps InheritedProvider.
- 核心逻辑,多种provider都直接或间接继承于InheritedProvider。
源码
class InheritedProvider<T> extends SingleChildStatelessWidget {
/// Creates a value, then expose it to its descendants.
///
/// The value will be disposed of when [InheritedProvider] is removed from
/// the widget tree.【这里说明了数据的生命周期和InheritedProvider的声明周期一致】
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);
/// 子节点的创建,优先builder
@override
Widget buildWithChild(BuildContext context, Widget? child) {
return _InheritedProviderScope<T?>(
owner: this,
debugType: kDebugMode ? '$runtimeType' : '',
child: builder != null
? Builder(
builder: (context) => builder!(context, child),
)
: child!,
);
}
}
- 数据管理 的功能代理给_delegate
- Widget 承接给_InheritedProviderScope,_InheritedProviderScope继承自InheritedWidget
builder说明
Syntax sugar for obtaining a BuildContext that can read the provider created.
- 语法糖,可在创建Provider的时候读取provider的内容
This code:
Provider (
create: (context) => 42,
builder: (context, child) {
final value = context.watch ();
return Text('$value');
}
)
is strictly equivalent to:
Provider (
create: (context) => 42,
child: Builder(
builder: (context) {
final value = context.watch ();
return Text('$value');
},
),
)
小结
InheritedProvider
数据部分: _delegate承接
widget部分 : _InheritedProviderScope承接
两部分联系: widget用过owner取数据
_InheritedProviderScope
内部类,重写InheritedWidget的功能。
源码
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);
}
}
通过owner获取父节点provider提供的数据。
_InheritedProviderScopeElement
定义
class _InheritedProviderScopeElement<T> extends InheritedElement
implements InheritedContext<T>
重写了InheritedElement,并实现了InheritedContext接口。
InheritedContext抽象类,定义如下:
abstract class InheritedContext<T> extends BuildContext {
/// The current value exposed by [InheritedProvider].
///
/// This property is lazy loaded, and reading it the first time may trigger
/// some side-effects such as creating a [T] instance or starting
/// a subscription.
T get value; /// 【获取InheritedWidget包装的数据】
/// Marks the [InheritedProvider] as needing to update dependents.
///
/// This bypass [InheritedWidget.updateShouldNotify] and will force widgets
/// that depends on [T] to rebuild.
void markNeedsNotifyDependents(); //【触发rebuild的入口】
/// Whether `setState` was called at least once or not.
///
/// It can be used by [DeferredStartListening] to differentiate between the
/// very first listening, and a rebuild after `controller` changed.
bool get hasValue;
}
下面按照接收到通知执行的逻辑分析源码
数据变化,首先会执行 markNeedsNotifyDependents
@override
void markNeedsNotifyDependents() {
if (!_isNotifyDependentsEnabled) {
return;
}
markNeedsBuild(); // 【标记需要重新build】
_shouldNotifyDependents = true;
}
看到会执行build的逻辑
@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();
}
_shouldNotifyDependents 从markNeedsNotifyDependents 方法中看到为ture, 所以会会执行notifyClients
[InheritedElement]
@override
void notifyClients(InheritedWidget oldWidget) {
/// 依次调用依赖的notifyDependent
for (final Element dependent in _dependents.keys) {
notifyDependent(oldWidget, dependent);
}
}
@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>) {
// select can never be used inside `didChangeDependencies`, so if the
// dependent is already marked as needed build, there is no point
// in executing the selectors.
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();
}
就是找到InheritedElement中存储的依赖,调用依赖的didChangeDependencies方法。
其中,dependencies is _Dependency的判断,为了处理Selector的情况,就是调用依赖的selectors回调,判断是否需要更新。
小结
- _InheritedProviderScopeElement 是provider 内部包装的InheritedElement;
- 通过get widget 取到widget, 然后通过widget的owner可取到provider的数据;
- 数据变化时,执行的回调 markNeedsNotifyDependents,触发InheritedElemen会build;
- InheritedElement的build,触发依赖的build;
- 重写了notifyDependent,通过selector完成过滤的功能。缩小build的范围;
数据变化的流程
markNeedsNotifyDependents -> markNeedsBuild -> build -> notifyClients[InheritedElement] -> notifyDependent - > dependent.didChangeDependencies()
到此widget部分梳理完成,下面是数据部分,数据部分有创建型和复用型,这里只看创建型的逻辑。
创建型数据模型_CreateInheritedProvider
源码
class _CreateInheritedProvider<T> extends _Delegate<T> {
_CreateInheritedProvider({
this.create,
this.update,
UpdateShouldNotify<T>? updateShouldNotify,
this.debugCheckInvalidValueType,
this.startListening,
this.dispose,
}) : assert(create != null || update != null),
_updateShouldNotify = updateShouldNotify;
final Create<T>? create;
final T Function(BuildContext context, T? value)? update;
final UpdateShouldNotify<T>? _updateShouldNotify;
final void Function(T value)? debugCheckInvalidValueType;
final StartListening<T>? startListening;
final Dispose<T>? dispose;
@override
_CreateInheritedProviderState<T> createState() =>
_CreateInheritedProviderState();
}
掌管了一堆回调, 具体的逻辑放在了state中。
abstract class _DelegateState<T, D extends _Delegate<T>> {
_InheritedProviderScopeElement<T?>? element;
// 获取数据的功能
T get value;
D get delegate => element!.widget.owner._delegate as D;
bool get hasValue;
bool debugSetInheritedLock(bool value) {
return element!._debugSetInheritedLock(value);
}
bool willUpdateDelegate(D newDelegate) => false;
void dispose() {}
void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
void build({required bool isBuildFromExternalSources}) {}
}
创建型state的数据获取方法定义如下:
@override
T get value {
bool? _debugPreviousIsInInheritedProviderCreate;
bool? _debugPreviousIsInInheritedProviderUpdate;
// 使用的时候懒初始化逻辑,调用create创建数据
if (!_didInitValue) {
_didInitValue = true;
if (delegate.create != null) {
assert(debugSetInheritedLock(true));
_value = delegate.create!(element!);
} catch (e, stackTrace) {
} finally {
}
}
if (delegate.update != null) {
try {
// 如果有update回调,执行update回调,这在proxy中有用,获取proxy依赖的provider的数据,组装新的数据
_value = delegate.update!(element!, _value);
} finally {
}
}
}
element!._isNotifyDependentsEnabled = false;
// 首次获取值,添加listener,并获取removeListener回调
_removeListener ??= delegate.startListening?.call(element!, _value as T);
element!._isNotifyDependentsEnabled = true;
return _value as T;
}
ChangeNotifierProvider小结
到此ChangeNotifierProvider讲解完成 大致回顾下结构。
provider的大致结构: