Provider的使用范例
在pubspec.yaml中引入provider插件后执行命令flutter pub get;
dependencies:
provider: ^6.0.5
同Stream、BLoC一样,Provider的基础结构也可分为logic、state、view三层;
首先定义state层,初始化需state实例以及相关数据;
class ProviderDemoState {
late int count;
ProviderDemoState() {
count = 0;
}
}
provider层,等同于logic层,用于绑定state层以及实现对state层数据的更新操作;
import 'provider_demo_state.dart';
class ProviderDemoProvider extends ChangeNotifier {
final state = ProviderDemoState();
void increment() {
state.count++;
notifyListeners();
}
}
view层,通过ChangeNotifierProvider定义状态管理的入口,在相应的widget中获取provider,通过Consumer包裹需要刷新的控件完成刷新;
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'provider_demo_provider.dart';
class ProviderDemoPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) => ProviderDemoProvider(),
builder: (context, child) => _buildPage(context),
);
}
Widget _buildPage(BuildContext context) {
final provider = context.read<ProviderDemoProvider>();
final state = provider.state;
return Scaffold(
appBar: AppBar(title: Text('Provider-范例')),
body: Center(
child: Consumer<ProviderDemoProvider>(
builder: (context, provider, child) {
return Text(
'You have pushed the button this many times: ${state.count} ',
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => provider.increment(),
child: Icon(Icons.add),
),
);
}
}
这样,就可以通过provider实现一个简单的点击按钮自动刷新页面文字内容的功能了。
前置知识
ChangeNotifier的使用
通常情况下,ChangeNotifier都是结合ChangeNotifierProvider在provider框架中使用,我们在provider层(logic层)定义的用来操作state层数据变化的类就是继承自ChangeNotifier,但实际上,ChangeNotifier也是可以单独使用的,例如TextFiled中的TextEditingController就是继承自ValueNotifier(ChangeNotifier的子类),通过监听每一次对TextEditingController.value的赋值操作,加以相应的逻辑判断,最终通过setState()方法实现控件的刷新。
我们看下ValueNotifier的源码:
class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {
ValueNotifier(this._value);
@override
T get value => _value;
T _value;
set value(T newValue) {
if (_value == newValue)
return;
_value = newValue;
notifyListeners();
}
@override
String toString() => '${describeIdentity(this)}($value)';
}
由源码可知,每次对ValueNotifier中的value(TextEditingController.value)进行set操作是,都会判断value的值是否有变化,如果有变化则调用notifyListeners()方法通知刷新;
我们可以仿写TextFiled的刷新逻辑自定义一个能实现自动刷新的组件:
先通过继承ChangeNotifier实现控制器类;
class TestNotifierController extends ChangeNotifier {
String _value = '0';
String get value => _value;
set value(String newValue) {
if (_value == newValue) return;
_value = newValue;
notifyListeners();
}
}
定义与控制器相搭配的widget;
class TestNotifierWidget extends StatefulWidget {
const TestNotifierWidget({
Key? key,
this.controller,
}) : super(key: key);
final TestNotifierController? controller;
@override
_TestNotifierState createState() => _TestNotifierState();
}
class _TestNotifierState extends State<TestNotifierWidget> {
@override
void initState() {
///添加回调 value改变时,自动触发回调内容
widget.controller?.addListener(_change);
super.initState();
}
@override
Widget build(BuildContext context) {
return Text(
widget.controller?.value ?? '初始值为空',
style: TextStyle(fontSize: 30.0),
);
}
///被触发的回调
void _change() {
setState(() {});
}
}
以上便完成了一个 可以通过改变控制器的数据,完成自动刷新的widget组件。
控件的使用:
class TestNotifierPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final controller = TestNotifierController();
var count = 0;
return Scaffold(
appBar: AppBar(title: Text('ChangeNotifier使用演示')),
body: Center(
child: TestNotifierWidget(controller: controller),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
count += 1;
controller.value = '数值变化:${count.toString()}';
},
child: Icon(Icons.add),
),
);
}
}
- 点击按钮,在onPressed()方法中改变控制器的数据,以达到自动刷新的效果。
Function call()
在源码中,可以看到大量的XXX.call()这样的方法调用的写法,实际上XXX.call()等效于XXX();
某些场景下,使用XXX.call()的方式可以帮助我们简化很多代码,例如:
class TestWidget extends StatelessWidget {
const TestWidget({
Key? key,
this.onTap,
this.onBack,
}) : super(key: key);
final VoidCallback? onTap;
final VoidCallback? onBack;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
if (onTap != null) {
onTap!();
}
if (onBack != null) {
onBack!();
}
},
child: Container(),
);
}
}
- 该场景下的onTap()、onBack()方法,如果不做判空操作且外部未实现对应方法的情况下,调用方法会报出异常;
使用XXX.call()的方式后,可以直接省略if判空的操作了;
class TestWidget extends StatelessWidget {
const TestWidget({
Key? key,
this.onTap,
this.onBack,
}) : super(key: key);
final VoidCallback? onTap;
final VoidCallback? onBack;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
onTap?.call();
onBack?.call();
},
child: Container(),
);
}
}
Provider的刷新机制-主流程
我们继承自ChangeNotifier的类,都是通过ChangeNotifierProvider传入到的Provider框架内部的,所以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,
);
...
static void _dispose(BuildContext context, ChangeNotifier? notifier) {
notifier?.dispose();
}
}
- 可以看到,ChangeNotifierProvider内部定义了一个_dispose()方法,方法销毁了传入的ChangeNotifier(XXXProvider的父类)实例,并将_dispose()方法传递给父类(ListenableProvider);
ListenableProvider的源码:
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,
);
...
static VoidCallback _startListening(InheritedContext e, Listenable? value,) {
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
}
- ListenableProvider内部定义了一个_startListening()方法,在方法内部对传入的Listenable实例添加了监听,_startListening()方法被传递给了父类(InheritedProvider);
InheritedProvider的源码:
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);
...
final _Delegate<T> _delegate;
final bool? _lazy;
final TransitionBuilder? 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!,
);
}
}
- InheritedProvider继承自SingleChildStatelessWidget(StatelessWidget的子类);
- buildWithChild()方法中返回了一个_InheritedProviderScope实例;
- SingleChildStatelessWidget中的buildWithChild()方法就相当于StatelessWidget中的build()方法;
_InheritedProviderScope的源码:
class _InheritedProviderScope<T> extends InheritedWidget {
const _InheritedProviderScope({
required this.owner,
required this.debugType,
required Widget child,
}) : 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);
}
}
- _InheritedProviderScope继承自InheritedWidget,所以在widget创建的时候就会调用其自身的createElement()方法;
- createElement()方法内部返回了一个_InheritedProviderScopeElement实例;
_InheritedProviderScopeElement的源码:
abstract class InheritedContext<T> extends BuildContext {
T get value;
void markNeedsNotifyDependents();
bool get hasValue;
}
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
...
@override
void mount(Element? parent, dynamic newSlot) {
...
}
@override
_InheritedProviderScope<T> get widget => super.widget as _InheritedProviderScope<T>;
@override
void reassemble() {
...
}
@override
void updateDependencies(Element dependent, Object? aspect) {
...
}
@override
void notifyDependent(InheritedWidget oldWidget, Element dependent) {
...
}
@override
void performRebuild() {
...
}
@override
void update(_InheritedProviderScope<T> newWidget) {
...
}
@override
void updated(InheritedWidget oldWidget) {
...
}
@override
void didChangeDependencies() {
...
}
@override
Widget build() {
...
}
@override
void unmount() {
...
}
@override
bool get hasValue => _delegateState.hasValue;
@override
void markNeedsNotifyDependents() {
...
}
bool _debugSetInheritedLock(bool value) {
...
}
@override
T get value => _delegateState.value;
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, {Object? aspect,}) {
...
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
...
}
}
- 这里省略了_InheritedProviderScopeElement中方法的实现(不然代码太多了);
- _InheritedProviderScopeElement继承自InheritedContext,而InheritedContext继承自BuildContext;
- BuildContext是一个抽象类,也就是说_InheritedProviderScopeElement中实现了BuildContext中所有的抽象方法;
- BuildContext中的抽象方法多与控件的生命周期挂钩(如performRebuild()、reassemble());
由上面流程可知,ChangeNotifierProvider在初始化时,经过逐层的回溯,最终会实例化一个_InheritedProviderScopeElement对象(BuildContext的实现),同时_InheritedProviderScopeElement内部的生命周期也被触发;由于Provider添加监听和刷新的逻辑都和_InheritedProviderScopeElement有关,因此,可以说在ChangeNotifierProvider在初始化时,ChangeNotifierProvider的子组件就拥有了状态管理的能力。
ChangeNotifierProvider的初始化流程如下图:
那么,Provider是如何通过_InheritedProviderScopeElement实现添加监听和刷新的呢?
Provider的刷新机制-添加监听
我们在使用Provider时,通常将一个继承自ChangeNotifier的类(XXXProvider)的实例通过create参数传递给ChangeNotifierProvider,实际上,Provider内部会调用XXXProvider实例的addListener()方法来实现监听,所以需要找到XXXProvider实例的addListener()方法实在什么位置被调用的。
create实例的传递
还是需要看ChangeNotifierProvider的源码:
typedef Create<T> = T Function(BuildContext context);
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,
);
...
static void _dispose(BuildContext context, ChangeNotifier? notifier) {
notifier?.dispose();
}
}
- 这里的Create是一个Function,返回了一个继承自ChangeNotifier的实例;
- 新增了_dispose()方法,传给了父类(ListenableProvider);
ListenableProvider的源码:
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,
);
...
static VoidCallback _startListening(InheritedContext e, Listenable? value,) {
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
}
- 此处将create和_startListening()方法传递给了父类(InheritedProvider);
InheritedProvider的源码:
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);
...
}
- 此处将子类传递归来的create实例、_dispose()方法、_startListening()方法传递给了_CreateInheritedProvider;
create实例传递的流程如下图:
_CreateInheritedProvider
_CreateInheritedProvider的源码:
@immutable
abstract class _Delegate<T> {
_DelegateState<T, _Delegate<T>> createState();
void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
}
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();
}
- _CreateInheritedProvider继承自抽象类_Delegate,实现了其createState()方法;
- createState()方法返回了一个_CreateInheritedProviderState实例,照理说,主要逻辑都应该在_CreateInheritedProviderState里;
- 这里的createState()方法与StatefulWidget中的createState()方法不同,_CreateInheritedProvider在初始化时不会主动调用createState()方法,所以在看_CreateInheritedProviderState的源码之前,我们先找到_CreateInheritedProvider中的createState()方法实在何处被调用的;
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);
...
final _Delegate<T> _delegate;
final bool? _lazy;
final TransitionBuilder? 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!,
);
}
}
- InheritedProvider实例的_delegate参数被赋值为一个_CreateInheritedProvider实例;
- buildWithChild()方法返回的_InheritedProviderScope实例有一个owner参数,参数值为InheritedProvider实例本身;
class _InheritedProviderScope<T> extends InheritedWidget {
const _InheritedProviderScope({
required this.owner,
required this.debugType,
required Widget child,
}) : 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);
}
}
- createElement()方法返回了一个_InheritedProviderScopeElement实例,关键部分在_InheritedProviderScopeElement中;
_InheritedProviderScopeElement的源码(精简后):
class _InheritedProviderScopeElement<T> extends InheritedElement
implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
...
@override
void performRebuild() {
if (_firstBuild) {
_firstBuild = false;
_delegateState = widget.owner._delegate.createState()..element = this;
}
super.performRebuild();
}
...
}
- 关键代码找到了!widget.owner._delegate.createState()..element = this;
- widget(_InheritedProviderScope)→ owner(InheritedProvider)→ _delegate(_CreateInheritedProvider);
- 可以看到,在_InheritedProviderScopeElement初始化(框架入口ChangeNotifierProvider初始化)时,经过一些列的回溯与调用,_CreateInheritedProviderState就已经被初始化了;
- 除了_CreateInheritedProviderState实例的初始化外,还将_InheritedProviderScopeElement实例本身赋值给_CreateInheritedProviderState实例的element属性,这个后面会讲到;
_CreateInheritedProvider的createState()方法调用流程如下:
根据以上流程我们可知,_CreateInheritedProvider中的createState()方法是在ChangeNotifierProvider初始化时就被调用的,因此我们可以接着去看_CreateInheritedProviderState的源码;
_CreateInheritedProviderState
_CreateInheritedProviderState的源码(精简后):
class _CreateInheritedProviderState<T> extends _DelegateState<T, _CreateInheritedProvider<T>> {
VoidCallback? _removeListener;
bool _didInitValue = false;
T? _value;
_CreateInheritedProvider<T>? _previousWidget;
@override
T get value {
...
if (!_didInitValue) {
_didInitValue = true;
if (delegate.create != null) {
assert(debugSetInheritedLock(true));
try {
...
_value = delegate.create!(element!);
} finally {
...
}
...
}
...
}
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);
}
}
...
}
- _CreateInheritedProviderState继承自_DelegateState;
- 在ChangeNotifierProvider的初始化流程中的_dispose()、_startListening()、create实例都在_CreateInheritedProviderState中被使用;
- 但以上的使用都要通过delegate,这个delegate是什么?盲猜是从父类(_DelegateState)继承而来的,我们去看下_DelegateState的源码;
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}) {}
}
果然,在_DelegateState中存在delegate属性
- 关键代码:element!.widget.owner._delegate;
- element(_InheritedProviderScopeElement实例)→ widget(_InheritedProviderScope实例)→ owner(InheritedProvider)→ _delegate(_CreateInheritedProvider)
- 由以上可知,_CreateInheritedProviderState中用来使用_dispose()、_startListening()、create实例等的delegate,就是ChangeNotifierProvider初始化时,在InheritedProvider中初始化的_delegate(_CreateInheritedProvider实例);
- 根据上面提到的,_InheritedProviderScopeElement中有一行关键代码:widget.owner._delegate.createState()..element = this 可知,delegate的element属性在_InheritedProviderScopeElement时就被赋值了,所以一定不为空;
_DelegateState.element的初始化流程如下:
class _CreateInheritedProviderState<T> extends _DelegateState<T, _CreateInheritedProvider<T>> {
VoidCallback? _removeListener;
bool _didInitValue = false;
T? _value;
_CreateInheritedProvider<T>? _previousWidget;
@override
T get value {
...
if (!_didInitValue) {
_didInitValue = true;
if (delegate.create != null) {
assert(debugSetInheritedLock(true));
try {
...
_value = delegate.create!(element!);
} finally {
...
}
...
}
...
}
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);
}
}
...
}
其中有两个关键流程:
1)get 流程:
- 我们传入的create会赋值给value属性,也就是说,现在的value属性就是我们一开始传入的XXXProvider实例;
- 下面调用了startListening()方法,参数为element和value;
- element即_InheritedProviderScopeElement实例,_InheritedProviderScopeElement继承自InheritedContext,相当于上下文实例;
- value即XXXProvider实例;
2)dispose 流程
- _CreateInheritedProviderState中定义了一个Callback → _removeListener,在调用startListening()方法时,_removeListener接收startListening()方法的返回值,并在dispose()方法中调用;
- startListening()是在ListenableProvider初始化时被定义,根据前文贴出的ListenableProvider源码可知,startListening()方法的返回值是一个移除监听的操作(value?.removeListener());
- 同时dispose()方法还调用了ChangeNotifierProvider初始化流程中定义的_dispose()方法(移除XXXProvider实例),至此,监听的回收流程也完成了;
最后还有一个问题,那就是_CreateInheritedProviderState中value的get方法是什么时候内调用的,其实在_InheritedProviderScopeElement的源码中有这样一段:
class _InheritedProviderScopeElement<T> extends InheritedElement
implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
late _DelegateState<T, _Delegate<T>> _delegateState;
...
@override
void performRebuild() {
if (_firstBuild) {
_firstBuild = false;
_delegateState = widget.owner._delegate.createState()..element = this;
}
super.performRebuild();
}
@override
void reassemble() {
super.reassemble();
final value = _delegateState.hasValue ? _delegateState.value : null;
if (value is ReassembleHandler) {
value.reassemble();
}
}
...
}
- 在reassemble()方法中,调用了_delegateState.value;
- reassemble()方法是Element的生命周期方法,在全局状态初始化后调用,即performRebuild()方法被调用后,Element的生命周期会调用reassemble()方法;
- reassemble()方法中的_delegateState在performRebuild()方法中被初始化(_delegateState = widget.owner._delegate.createState()..element = this;);
总结
根据以上的梳理,可以总结下Provider的初始化以及调用流程,如下:
Provider的刷新机制-刷新逻辑
刷新触发与刷新流程
由以上分析可知,刷新触发的代码在ListenableProvider中,当XXXProvider实例收到通知消息(外部调用notifyListeners()方法)时,会触发value?.addListener(e.markNeedsNotifyDependents)方法;
ListenableProvider的源码:
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,
);
...
static VoidCallback _startListening(InheritedContext e, Listenable? value,) {
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
}
因此刷新的关键逻辑就在e.markNeedsNotifyDependents的实现中,markNeedsNotifyDependents是通过InheritedContext这个上下文类来调用的;
而在Provider中,使用了_InheritedProviderScopeElement作为InheritedContext的实现类,因此我们需要看下_InheritedProviderScopeElement的源码:
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
...
@override
void markNeedsNotifyDependents() {
if (!_isNotifyDependentsEnabled) {
return;
}
markNeedsBuild();
_shouldNotifyDependents = true;
}
...
}
- 这里省略了其他代码,只保留markNeedsNotifyDependents()方法有关的代码;
- markNeedsNotifyDependents()中除了调用了markNeedsBuild()方法外就没有其他逻辑了,我们需要看下markNeedsBuild()方法的实现;
markNeedsBuild()是Element类中的方法(_InheritedProviderScopeElement → InheritedElement → ProxyElement → ComponentElement→ Element),我们看下markNeedsBuild()的实现:
abstract class Element extends DiagnosticableTree implements BuildContext {
...
/// Marks the element as dirty and adds it to the global list of widgets to
/// rebuild in the next frame.
///
/// Since it is inefficient to build an element twice in one frame,
/// applications and widgets should be structured so as to only mark
/// widgets dirty during event handlers before the frame begins, not during
/// the build itself.
void markNeedsBuild() {
assert(_lifecycleState != _ElementLifecycle.defunct);
if (_lifecycleState != _ElementLifecycle.active)
return;
assert(owner != null);
assert(_lifecycleState == _ElementLifecycle.active);
assert(() {
if (owner!._debugBuilding) {
assert(owner!._debugCurrentBuildTarget != null);
assert(owner!._debugStateLocked);
if (_debugIsInScope(owner!._debugCurrentBuildTarget!))
return true;
if (!_debugAllowIgnoredCallsToMarkNeedsBuild) {
final List<DiagnosticsNode> information = <DiagnosticsNode>[
ErrorSummary('setState() or markNeedsBuild() called during build.'),
ErrorDescription(
'This ${widget.runtimeType} widget cannot be marked as needing to build because the framework '
'is already in the process of building widgets. A widget can be marked as '
'needing to be built during the build phase only if one of its ancestors '
'is currently building. This exception is allowed because the framework '
'builds parent widgets before children, which means a dirty descendant '
'will always be built. Otherwise, the framework might not visit this '
'widget during this build phase.',
),
describeElement(
'The widget on which setState() or markNeedsBuild() was called was',
),
];
if (owner!._debugCurrentBuildTarget != null)
information.add(owner!._debugCurrentBuildTarget!.describeWidget('The widget which was currently being built when the offending call was made was'));
throw FlutterError.fromParts(information);
}
assert(dirty); // can only get here if we're not in scope, but ignored calls are allowed, and our call would somehow be ignored (since we're already dirty)
} else if (owner!._debugStateLocked) {
assert(!_debugAllowIgnoredCallsToMarkNeedsBuild);
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('setState() or markNeedsBuild() called when widget tree was locked.'),
ErrorDescription(
'This ${widget.runtimeType} widget cannot be marked as needing to build '
'because the framework is locked.',
),
describeElement('The widget on which setState() or markNeedsBuild() was called was'),
]);
}
return true;
}());
if (dirty)
return;
_dirty = true;
owner!.scheduleBuildFor(this);
}
/// Called by the [BuildOwner] when [BuildOwner.scheduleBuildFor] has been
/// called to mark this element dirty, by [mount] when the element is first
/// built, and by [update] when the widget has changed.
@pragma('vm:prefer-inline')
void rebuild() {
assert(_lifecycleState != _ElementLifecycle.initial);
if (_lifecycleState != _ElementLifecycle.active || !_dirty)
return;
assert(() {
debugOnRebuildDirtyWidget?.call(this, _debugBuiltOnce);
if (debugPrintRebuildDirtyWidgets) {
if (!_debugBuiltOnce) {
debugPrint('Building $this');
_debugBuiltOnce = true;
} else {
debugPrint('Rebuilding $this');
}
}
return true;
}());
assert(_lifecycleState == _ElementLifecycle.active);
assert(owner!._debugStateLocked);
Element? debugPreviousBuildTarget;
assert(() {
debugPreviousBuildTarget = owner!._debugCurrentBuildTarget;
owner!._debugCurrentBuildTarget = this;
return true;
}());
performRebuild();
assert(() {
assert(owner!._debugCurrentBuildTarget == this);
owner!._debugCurrentBuildTarget = debugPreviousBuildTarget;
return true;
}());
assert(!_dirty);
}
/// Called by rebuild() after the appropriate checks have been made.
@protected
void performRebuild();
}
这里花里胡哨的写了一大堆,由于markNeedsBuild()内部的调用流程过于抽象,因此这里不再做具体的源码分析,不过根据markNeedsBuild()的方法注释可知,markNeedsBuild()被调用后会将Element实例打上脏标记,并缓存在一个全局的列表中;
- 关键代码在owner!.scheduleBuildFor(this)中,这里是将Element实例打上脏标记,并缓存在全局的列表中的具体实现;
- 另一个关键方法rebuild(),我们根据方法注释可知,该方法会在owner!.scheduleBuildFor()方法被调用后执行(由于调用过程过于抽象,在这不做具体分析了,感兴趣的小伙伴可以研究下);
- 最终,我们发现在rebuild()方法的内部调用了performRebuild()方法;
调用流程:Element.performRebuild() → ComponentElement.performRebuild() → ComponentElement.build() → _InheritedProviderScopeElement.build();
总结一下Provider的刷新流程:
- 当外部调用notifyListeners()方法时,会触发XXXProvider实例的addListener()方法,进而调用InheritedContext类中的markNeedsNotifyDependents()方法;
- markNeedsNotifyDependents()方法内部会经过一些列的调用逻辑,最终调用其自身的performRebuild()方法;
- InheritedContext类中performRebuild()方法的实现在其子类ComponentElement类中;
- ComponentElement中的performRebuild()方法会调用其自身的build()方法,方法实现在其子类_InheritedProviderScopeElement类中;
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
bool _shouldNotifyDependents = false;
...
@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();
}
...
}
- 由于上面的markNeedsNotifyDependents()方法中已经给_shouldNotifyDependents设置为true,所以build内部逻辑会执行notifyClients;
- notifyClients()方法的实现在其父类(InheritedElement)中;
由于InheritedElement中notifyClients()方法的具体实现涉及到太多层级的调用、Bind类、绘制流程等,因此这里不再贴源码进行分析,其内部实现的大体逻辑如下:
- 遍历全局HashMap – _dependents的所有key,取到对应的Element(_dependents的Key为Element类型);
- 每获取到一个Element实例,都会调用Element内部的didChangeDependencies()方法;
- didChangeDependencies()方法内部将当前Element打上一个标记,并调用与当前Element实例对应的widget实例的build方法;
-
而被打上标记的Element所对应的widget,我们根据以上流程也能看出来,就是前文所提到的Consumer;
刷新流程.png
BuildContext
在上述的Provider源码分析中,我们发现其逻辑会大量的涉及到BuildContext类以及其相关类中的内容,那么这里我们来简单看一下BuildContext类究竟是什么。
BuildContext的源码:
abstract class BuildContext {
Widget get widget;
BuildOwner? get owner;
bool get debugDoingBuild;
RenderObject? findRenderObject();
Size? get size;
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect });
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object? aspect });
InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>();
T? findAncestorWidgetOfExactType<T extends Widget>();
T? findAncestorStateOfType<T extends State>();
T? findRootAncestorStateOfType<T extends State>();
T? findAncestorRenderObjectOfType<T extends RenderObject>();
void visitAncestorElements(bool Function(Element element) visitor);
void visitChildElements(ElementVisitor visitor);
DiagnosticsNode describeElement(String name, {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty});
DiagnosticsNode describeWidget(String name, {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty});
List<DiagnosticsNode> describeMissingAncestor({ required Type expectedAncestorType });
DiagnosticsNode describeOwnershipChain(String name);
}
我们可以看到,BuildContext是一个抽象类,约定了相关的功能,在不同的实现类中,相关方法的实现可能会有出入,但是不应偏离抽象方法注释所描述的功能范围;
最常见的BuildContext的实现类就是StatelessWidget(StatefulWidget的实现同理),我们来看下StatelessWidget类的源码:
abstract class StatelessWidget extends Widget {
const StatelessWidget({ Key? key }) : super(key: key);
@override
StatelessElement createElement() => StatelessElement(this);
@protected
Widget build(BuildContext context);
}
class StatelessElement extends ComponentElement {
StatelessElement(StatelessWidget widget) : super(widget);
@override
StatelessWidget get widget => super.widget as StatelessWidget;
@override
Widget build() => widget.build(this);
@override
void update(StatelessWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
_dirty = true;
rebuild();
}
}
- StatelessWidget抽象了build()方法,入参为BuildContext;
- createElement()方法中实例化了StatelessElement类,并将自身(StatelessWidget实例)传入;
- StatelessElement类中实现了ComponentElement类的build()方法,并在内部调用widget(传入的StatelessWidget实例)的build()方法;
abstract class ComponentElement extends Element {
...
@protected
Widget build();
...
}
abstract class Element extends DiagnosticableTree implements BuildContext {
...
}
- ComponentElement继承Element,它抽象了一个build方法,StatelessElement实现了这个方法;
- Element继承自实现了BuildContext的DiagnosticableTree类;
- 可以这样理解:每个Widget都有对应的Element( 通过createElement()生成 ),Element是BuildContext实现类;
@immutable
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key? key;
@protected
@factory
Element createElement();
...
}
由于Widget类中抽象了createElement()方法,相当于每一个Widget的子类都有与其自身相对应的Element();

####Provider.of<T>()
为了将上面的流程串联起来,Provider使用了Provider.of()方法将刷新组件添加到InheritedElement中的_dependents变量里;
static T of<T>(BuildContext context, {bool listen = true}) {
...
final inheritedElement = _inheritedElementOf<T>(context);
if (listen) {
context.dependOnInheritedElement(inheritedElement);
}
return inheritedElement.value;
}
static _InheritedProviderScopeElement<T> _inheritedElementOf<T>(BuildContext context) {
...
_InheritedProviderScopeElement<T>? inheritedElement;
if (context.widget is _InheritedProviderScope<T>) {
context.visitAncestorElements((parent) {
inheritedElement = parent.getElementForInheritedWidgetOfExactType<
_InheritedProviderScope<T>>() as _InheritedProviderScopeElement<T>?;
return false;
});
} else {
inheritedElement = context.getElementForInheritedWidgetOfExactType<
_InheritedProviderScope<T>>() as _InheritedProviderScopeElement<T>?;
}
if (inheritedElement == null) {
throw ProviderNotFoundException(T, context.widget.runtimeType);
}
return inheritedElement!;
}
- of()方法中,会通过_inheritedElementOf<T>()方法获取到父组件节点中距离最近的继承自InheritedElement的XXXElement实例;
- 在_inheritedElementOf<T>()方法内部,是通过 context.getElementForInheritedWidgetOfExactType()来实现的,继承自InheritedElement的Widget的子节点,可以通过该方法找到父组件节点中距离最近的继承自InheritedElement的XXXElement实例;
- 拿到XXXElement实例之后,通过调用context.dependOnInheritedElement()方法,为当前的widget添加依赖;
abstract class Element extends DiagnosticableTree implements BuildContext {
...
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies!.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
...
}
- 这里面调用了ancestor.updateDependencies()方法,传入了当前widget对应的Element本身,以及继承自InheritedElement的XXXElement实例;
ancestor.updateDependencies()方法的实现:
class InheritedElement extends ProxyElement {
...
@protected
void setDependencies(Element dependent, Object? value) {
_dependents[dependent] = value;
}
@protected
void updateDependencies(Element dependent, Object? aspect) {
setDependencies(dependent, null);
}
...
}
- 方法内部调用了setDependencies方法;
- setDependencies方法,将子Widget的Element实例赋值给了继承InheritedElement的类的 _dependents 变量;
自定义Builder
通过上面的分析,我们已经了解了provider的刷新机制,我们可以自定义一个Build来代替provider中Consumer的作用;
builder代码如下:
class NewBuilder<T> extends StatelessWidget {
const NewBuilder(
this.builder, {
Key? key,
}) : super(key: key);
final Widget Function() builder;
@override
Widget build(BuildContext context) {
Provider.of<T>(context);
return builder();
}
}
provider层:
class CustomBuilderProvider extends ChangeNotifier {
int count = 0;
void increment() {
count++;
notifyListeners();
}
}
view层:
class CustomBuilderPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) => CustomBuilderProvider(),
builder: (context, child) => _buildPage(context),
);
}
Widget _buildPage(BuildContext context) {
final provider = context.read<CustomBuilderProvider>();
return Scaffold(
appBar: AppBar(title: Text('Provider-自定义Builder范例')),
body: Center(
child: NewBuilder<CustomBuilderProvider>(
() => Text(
'点击了 ${provider.count} 次',
style: TextStyle(fontSize: 30.0),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => provider.increment(),
child: Icon(Icons.add),
),
);
}
}
以上便完成了通过自定义builder实现一个简单的点击按钮自动刷新页面文字内容的功能了。
MultiProvider
一般情况下,我们在main主入口写全局Provider的时候,会使用MultiProvider,如下:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(builder: (BuildContext context, Widget? child) {
return MultiProvider(child: child, providers: [
//此处通过MultiProvider创建的Provider是全局的
ChangeNotifierProvider.value(value: ProSpanOneProvider()),
]);
});
}
}
那么MultiProvider都做了什么呢?我们来看下MultiProvider的源码:
class MultiProvider extends Nested {
MultiProvider({
Key? key,
required List<SingleChildWidget> providers,
Widget? child,
TransitionBuilder? builder,
}) : super(
key: key,
children: providers,
child: builder != null
? Builder(
builder: (context) => builder(context, child),
)
: child,
);
}
- MultiProvider继承自Nested类,Nested可以优化一些布局嵌套问题,感兴趣的可查看Nested Pub;
- 可以看到,MultiProvider将Provider实例套在了顶层的widget上;
Consumer
Consumer是使用provider过程中最常用的一个控件,我们来看看Consumer的源码:
class Consumer<T> extends SingleChildStatelessWidget {
Consumer({
Key? key,
required this.builder,
Widget? child,
}) : super(key: key, child: child);
final Widget Function(BuildContext context, T value, Widget? child,) builder;
@override
Widget buildWithChild(BuildContext context, Widget? child) {
return builder(
context,
Provider.of<T>(context),
child,
);
}
}
- Consumer内部重写了buildWithChild()方法,内部调用了Provider.of<T>()方法;
- 所以Consumer的本质就是一个可以获取最近父控件的InIneritedElement实例,并与自身绑定依赖(可获取刷新能力)的widget;