1 什么是状态?什么是状态管理?
数据即为状态。从数据变化到通知界面更新的过程,我们称之为状态管理,状态管理要尽可能的把这个过程独立出来,让动态界面如同静态页面一般简单。
大到页面的路由变化,小到页面的数据发生变化,我们开发中每时每刻都离不开状态,有一位伟人曾说过,一切皆数据,那么今天就让我们从浅入深的揭开状态管理的神秘面纱。
如果还完全没有使用过Provider
的同学请移步:新手入门
2 从Provider看状态管理
import 'package:flutter/material.dart';
class MyModel3 with ChangeNotifier {
MyModel3({this.counter=0});
int counter = 0;
Future<void> incrementCounter() async {
// await Future.delayed(Duration(seconds: 2));
counter++;
print(counter);
notifyListeners();
}
@override
void dispose() {
// TODO: implement dispose
print('MyModel3 dispose');
super.dispose();
}
}
class ProviderDebugPage3 extends StatelessWidget {
final String title;
ProviderDebugPage3({this.title});
@override
Widget build(BuildContext context) {
print('---provider build ---');
return ChangeNotifierProvider(
create: (context) => MyModel3(),
child: Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Column(
children: <Widget>[
Consumer<MyModel3>(
// 获取到provider提供出来的值
builder: (context, model, child) {
return Container(
margin: const EdgeInsets.only(top: 20),
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.all(20),
alignment: Alignment.center,
color: Colors.lightGreen,
child: Text(
'Model3当前是:${model.counter}',
),
);
},
),
Consumer<MyModel3>(
// 获取到provider提供出来的值
builder: (context, model, child) {
return FlatButton(
color: Colors.tealAccent,
onPressed: model.incrementCounter,
child: Icon(Icons.add));
},
),
],
),
),
);
}
}
上面是我们通常使用的ChangeNotifierProvider
,这里用到了3个类ChangeNotifierProvider
、ChangeNotifier
、Consumer
,其中核心类是ChangeNotifierProvider
,它和ChangeNotifier
是观察者模式,和Consumer
是生产者消费者模式,达到的目的是,即使是StatelessWidget
,当数据MyModel3
发生变化时,对应的UI也能一起刷新,实现了从数据变化到更新UI的自动化过程,这里并不像我们使用StatefulWidget
的setState
,数据变化是自动引起UI刷新的,那么围绕核心类ChangeNotifierProvider
,我们去源码一探究竟。
3 ChangeNotifierProvider 源码分析
class ChangeNotifierProvider<T extends ChangeNotifier>
extends ListenableProvider<T> {
/// Creates a [ChangeNotifier] using `create` and automatically
/// dispose it when [ChangeNotifierProvider] is removed from the widget tree.
///
/// `create` must not be `null`.
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
是一个泛型类,泛型T是继承ChangeNotifier
类的,ChangeNotifierProvider
初始化的时候,多加了一个_dispose
方法,其余参数都传给了父类ListenableProvider
,这里解释了,为什么MyModel3
在页面析构的时候也会自动调用dispose
,是因为当系统回调ChangeNotifierProvider
的_dispose
方法时,_dispose
里面调用了MyModel3
的dispose
3.1 ListenableProvider 源码分析
class ListenableProvider<T extends Listenable> extends InheritedProvider<T> {
/// Creates a [Listenable] using [create] and subscribes to it.
///
/// [dispose] can optionally passed to free resources
/// when [ListenableProvider] is removed from the tree.
///
/// [create] must not be `null`.
ListenableProvider({
Key key,
@required Create<T> create,
Dispose<T> dispose,
bool lazy,
TransitionBuilder builder,
Widget child,
}) : assert(create != null),
super(
key: key,
startListening: _startListening,
create: create,
dispose: dispose,
debugCheckInvalidValueType: kReleaseMode
? null
: (value) {
if (value is ChangeNotifier) {
// ignore: invalid_use_of_protected_member
assert(!value.hasListeners, '''
The default constructor of ListenableProvider/ChangeNotifierProvider
must create a new, unused Listenable.
If you want to reuse an existing Listenable, use the second constructor:
- DO use ChangeNotifierProvider.value to provider 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: ...
)
''');
}
},
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<Listenable> e,
Listenable value,
) {
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
}
同样是泛型类,在这里又增加了一个_startListening
方法,实现是的功能是:
1 订阅事件,当接受到事件时,通知Element更新UI
2 返回一个默认取消订阅的回调
相比于ChangeNotifierProvider
这里我们遇到InheritedContext
和updateShouldNotify
,先mark下,继续往下。
3.2 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({
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);
...省略以下代码
}
相比于ListenableProvider
这里参数又增加了update
,并且出现了新的属性_delegate
看定义
final _Delegate<T> _delegate;
这里之前的参数都传给了_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();
}
class _CreateInheritedProviderState<T>
extends _DelegateState<T, _CreateInheritedProvider<T>> {
VoidCallback _removeListener;
bool _didInitValue = false;
T _value;
_CreateInheritedProvider<T> _previousWidget;
}
至此,从ChangeNotifierProvider
传递进来的参数都存在了_CreateInheritedProvider
里了,而_CreateInheritedProvider
的父类是一个抽象类_Delegate
abstract class _Delegate<T> {
_DelegateState<T, _Delegate<T>> createState();
void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
}
abstract class _DelegateState<T, D extends _Delegate<T>>
_DelegateState
类也是泛型类,有两个泛型T
和D
,其中D
是继承_Delegate<T>
的,那我们看看具体的实现类_CreateInheritedProviderState
class _CreateInheritedProviderState<T>
extends _DelegateState<T, _CreateInheritedProvider<T>> {
VoidCallback _removeListener;
bool _didInitValue = false;
T _value;
_CreateInheritedProvider<T> _previousWidget;
@override
T get value {
bool _debugPreviousIsInInheritedProviderCreate;
bool _debugPreviousIsInInheritedProviderUpdate;
assert(() {
_debugPreviousIsInInheritedProviderCreate =
debugIsInInheritedProviderCreate;
_debugPreviousIsInInheritedProviderUpdate =
debugIsInInheritedProviderUpdate;
return true;
}());
if (!_didInitValue) {
_didInitValue = true;
if (delegate.create != null) {
assert(debugSetInheritedLock(true));
try {
assert(() {
debugIsInInheritedProviderCreate = true;
debugIsInInheritedProviderUpdate = false;
return true;
}());
_value = delegate.create(element);
} finally {
assert(() {
debugIsInInheritedProviderCreate =
_debugPreviousIsInInheritedProviderCreate;
debugIsInInheritedProviderUpdate =
_debugPreviousIsInInheritedProviderUpdate;
return true;
}());
}
assert(debugSetInheritedLock(false));
assert(() {
delegate.debugCheckInvalidValueType?.call(_value);
return true;
}());
}
if (delegate.update != null) {
try {
assert(() {
debugIsInInheritedProviderCreate = false;
debugIsInInheritedProviderUpdate = true;
return true;
}());
_value = delegate.update(element, _value);
} finally {
assert(() {
debugIsInInheritedProviderCreate =
_debugPreviousIsInInheritedProviderCreate;
debugIsInInheritedProviderUpdate =
_debugPreviousIsInInheritedProviderUpdate;
return true;
}());
}
assert(() {
delegate.debugCheckInvalidValueType?.call(_value);
return true;
}());
}
}
element._isNotifyDependentsEnabled = false;
_removeListener ??= delegate.startListening?.call(element, _value);
element._isNotifyDependentsEnabled = true;
assert(delegate.startListening == null || _removeListener != null);
return _value;
}
@override
void dispose() {
super.dispose();
_removeListener?.call();
if (_didInitValue) {
delegate.dispose?.call(element, _value);
}
}
@override
void build({bool isBuildFromExternalSources}) {
var shouldNotify = false;
// Don't call `update` unless the build was triggered from `updated`/`didChangeDependencies`
// otherwise `markNeedsNotifyDependents` will trigger unnecessary `update` calls
if (isBuildFromExternalSources &&
_didInitValue &&
delegate.update != null) {
final previousValue = _value;
bool _debugPreviousIsInInheritedProviderCreate;
bool _debugPreviousIsInInheritedProviderUpdate;
assert(() {
_debugPreviousIsInInheritedProviderCreate =
debugIsInInheritedProviderCreate;
_debugPreviousIsInInheritedProviderUpdate =
debugIsInInheritedProviderUpdate;
return true;
}());
try {
assert(() {
debugIsInInheritedProviderCreate = false;
debugIsInInheritedProviderUpdate = true;
return true;
}());
_value = delegate.update(element, _value);
} finally {
assert(() {
debugIsInInheritedProviderCreate =
_debugPreviousIsInInheritedProviderCreate;
debugIsInInheritedProviderUpdate =
_debugPreviousIsInInheritedProviderUpdate;
return true;
}());
}
if (delegate._updateShouldNotify != null) {
shouldNotify = delegate._updateShouldNotify(previousValue, _value);
} else {
shouldNotify = _value != previousValue;
}
if (shouldNotify) {
assert(() {
delegate.debugCheckInvalidValueType?.call(_value);
return true;
}());
if (_removeListener != null) {
_removeListener();
_removeListener = null;
}
_previousWidget?.dispose?.call(element, previousValue);
}
}
if (shouldNotify) {
element._shouldNotifyDependents = true;
}
_previousWidget = delegate;
return super.build(isBuildFromExternalSources: isBuildFromExternalSources);
}
@override
bool get hasValue => _didInitValue;
}
因为T get value
还没用到,我们focus在build
,由于父类_DelegateState
是抽象类,这里重写了build
方法,这里用到了两个属性,delegate
和element
,都是父类中定义的,delegate
也是element
中取到的
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}) {}
}
那我们看看element
是怎么来的,首先,类型是_InheritedProviderScopeElement<T>
,我们找到创建对象的地方:_InheritedProviderScope
中有个createElement
方法可以返回这样的element
,但从dart代码上我们没追踪到谁调用了createElement
,我们先mark一下,谁调用了createElement
class _InheritedProviderScope<T> extends InheritedWidget {
const _InheritedProviderScope({
this.owner,
@required Widget child,
}) : super(child: child);
final InheritedProvider<T> owner;
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
return false;
}
@override
_InheritedProviderScopeElement<T> createElement() {
return _InheritedProviderScopeElement<T>(this);
}
}
class _InheritedProviderScopeElement<T> extends InheritedElement
implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
bool _shouldNotifyDependents = false;
bool _debugInheritLocked = false;
bool _isNotifyDependentsEnabled = true;
bool _firstBuild = true;
bool _updatedShouldNotify = false;
bool _isBuildFromExternalSources = false;
_DelegateState<T, _Delegate<T>> _delegateState;
@override
_InheritedProviderScope<T> get widget =>
super.widget as _InheritedProviderScope<T>;
...以下代码省略
}
说到这个_InheritedProviderScope
类,存在着继承关系:_InheritedProviderScope
->InheritedWidget
>ProxyWidget
->Widget
,本质上是一个Widget
,在构造的时候,外面传入了owner
,也就是InheritedProvider
,这样就在Widget
里面持有了InheritedProvider
,那在创建_InheritedProviderScopeElement
时传入了this
,也就把InheritedProvider
带给了InheritedElement
(_InheritedProviderScopeElement
的父类,继承关系:_InheritedProviderScopeElement
->InheritedElement
->ProxyElement
->ComponentElement
->Element
->DiagnosticableTree
),所以本质还是Element
,如果对Widget
、Element
还不太清楚的,可以参考这篇文章,实际视图的刷新逻辑都是在Element
中,本节我们暂不深入分析视图刷新的逻辑,先回到上说的_CreateInheritedProviderState
另外一个属性delegate
,
D get delegate => element.widget.owner._delegate as D;
这里我们看到,之前element
持有了_InheritedProviderScope
的widget
,widget
的owner
是InheritedProvider
,element.widget.owner._delegate
就是InheritedProvider
的属性_delegate
,是通过_CreateInheritedProvider
创建的,这里就整个都串起来了。
上面都是对
ChangeNotifierProvider
进行的深入分析,我们留下几个疑问:
1、InheritedContext
和updateShouldNotify
是做什么的
2、 谁调用了createElement
带着问题我们开启Consumer
的源码分析
4 Consumer 源码分析
Consumer
和ChangeNotifierProvider
是生产者和消费者模式,那生产的是什么?消费的又是什么呢?
class Consumer<T> extends SingleChildStatelessWidget {
/// {@template provider.consumer.constructor}
/// Consumes a [Provider<T>]
/// {@endtemplate}
Consumer({
Key key,
@required this.builder,
Widget child,
}) : assert(builder != null),
super(key: key, child: child);
/// {@template provider.consumer.builder}
/// Build a widget tree based on the value from a [Provider<T>].
///
/// Must not be `null`.
/// {@endtemplate}
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
是一个Widget
,这个没问题,我们在写的时候,就是把Consumer
当成widget
用的,Consumer
的参数都传递到了父类SingleChildStatelessWidget
,SingleChildStatelessWidget
是一个抽象类,里面存储了传入的child
abstract class SingleChildStatelessWidget extends StatelessWidget
implements SingleChildWidget {
/// Creates a widget that has exactly one child widget.
const SingleChildStatelessWidget({Key key, Widget child})
: _child = child,
super(key: key);
final Widget _child;
/// A [build] method that receives an extra `child` parameter.
///
/// This method may be called with a `child` different from the parameter
/// passed to the constructor of [SingleChildStatelessWidget].
/// It may also be called again with a different `child`, without this widget
/// being recreated.
Widget buildWithChild(BuildContext context, Widget child);
@override
Widget build(BuildContext context) => buildWithChild(context, _child);
@override
SingleChildStatelessElement createElement() {
return SingleChildStatelessElement(this);
}
}
并且Consumer
重写了抽象类SingleChildStatelessWidget
定义的buildWithChild
。
buildWithChild
这个也是系统调用的方法,buildWithChild
回调的时候,会接收一个child
参数,这个参数可能和SingleChildStatelessWidget
的构造函数传递进去的不一样,当控件没有被重新创建的时候也会再次调用并传递不同的child
,大致的意思就是,不管你传进来的child
是否变化,buildWithChild
都可能带着新的child
再次回调,buildWithChild
的实现里返回的是一个builder
,里面的参数value
传递的是Provider.of<T>(context)
,这就和Provider
建立起关系了,传进来的builder
是用来构建一个widget tree的,这个值一定不能为null,大概理解下就是buildWithChild
是用Consumer
传进来的builder
构建并返回一个新的Widget
,使用的参数是系统回调child
,但这个child
我们通常没有用,最终这个builder
的执行将会调用下面红色箭头处的代码。
小结:系统调用buildWithChild
,buildWithChild
调用builder
来将widget tree变成element tree。
而传递的
model
就是Provider.of<T>(context)
,这也就是为什么我们通常用类似下面的写法也可以得到相同的效果
class ProviderDebugPage1 extends StatelessWidget {
final String title;
ProviderDebugPage1({this.title});
@override
Widget build(BuildContext context) {
print('---provider build ---');
return Scaffold(
appBar: AppBar(
title: Text(this.title),
),
body: Column(
children: <Widget>[
Builder(
builder: (context) {
// 获取到provider提供出来的值
MyModel1 _model = Provider.of<MyModel1>(context, listen: false);
return Container(
margin: const EdgeInsets.only(top: 20),
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.all(20),
alignment: Alignment.center,
color: Colors.lightBlueAccent,
child: Text('不监听Model1当前是:${_model.counter}'));
},
),
Consumer<MyModel1>(
// 获取到provider提供出来的值
builder: (context, model, child) {
return Container(
margin: const EdgeInsets.only(top: 20),
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.all(20),
alignment: Alignment.center,
color: Colors.lightGreen,
child: Text('Model1当前是:${model.counter}',
),
);
},
),
Consumer<MyModel2>(
// 获取到provider提供出来的值
builder: (context, model, child) {
return FlatButton(
color: Colors.tealAccent,
onPressed:model.incrementCounter,
child: Icon(Icons.add));
},
),
);
}
}
原因就是Consumer
里面封装了Provider.of
,简单说就是,Consumer
内置了builder
的功能,并且Model
对象被主动回传了。好了,是时候看一下非常重要的Provider.of<T>(context)
了
class Provider<T> extends InheritedProvider<T> {
/// Creates a value, store it, and expose it to its descendants.
///
/// The value can be optionally disposed using [dispose] callback.
/// This callback which will be called when [Provider] is unmounted from the
/// widget tree.
Provider({
Key key,
@required Create<T> create,
Dispose<T> dispose,
bool lazy,
TransitionBuilder builder,
Widget child,
}) : assert(create != null),
super(
key: key,
lazy: lazy,
builder: builder,
create: create,
dispose: dispose,
debugCheckInvalidValueType: kReleaseMode
? null
: (T value) =>
Provider.debugCheckInvalidValueType?.call<T>(value),
child: child,
);
/// Expose an existing value without disposing it.
///
/// {@template provider.updateshouldnotify}
/// `updateShouldNotify` can optionally be passed to avoid unnecessarily
/// rebuilding dependents when [Provider] is rebuilt but `value` did not change.
///
/// Defaults to `(previous, next) => previous != next`.
/// See [InheritedWidget.updateShouldNotify] for more information.
/// {@endtemplate}
Provider.value({
Key key,
@required T value,
UpdateShouldNotify<T> updateShouldNotify,
TransitionBuilder builder,
Widget child,
}) : assert(() {
Provider.debugCheckInvalidValueType?.call<T>(value);
return true;
}()),
super.value(
key: key,
builder: builder,
value: value,
updateShouldNotify: updateShouldNotify,
child: child,
);
/// Obtains the nearest [Provider<T>] up its widget tree and returns its
/// value.
///
/// If [listen] is `true`, later value changes will trigger a new
/// [State.build] to widgets, and [State.didChangeDependencies] for
/// [StatefulWidget].
///
/// `listen: false` is necessary to be able to call `Provider.of` inside
/// [State.initState] or the `create` method of providers like so:
///
/// ```dart
/// Provider(
/// create: (context) {
/// return Model(Provider.of<Something>(context, listen: false)),
/// },
/// )
/// ```
static T of<T>(BuildContext context, {bool listen = true}) {
assert(context != null);
assert(
context.owner.debugBuilding ||
listen == false ||
debugIsInInheritedProviderUpdate,
'''
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.
To fix, write:
Provider.of<$T>(context, listen: false);
It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.
The context used was: $context
''',
);
final inheritedElement = _inheritedElementOf<T>(context);
if (listen) {
context.dependOnInheritedElement(inheritedElement);
}
return inheritedElement.value;
}
static _InheritedProviderScopeElement<T> _inheritedElementOf<T>(
BuildContext context,
) {
assert(context != null, '''
Tried to call context.read/watch/select or similar on a `context` that is null.
This can happen if you used the context of a StatefulWidget and that
StatefulWidget was disposed.
''');
assert(
_debugIsSelecting == false,
'Cannot call context.read/watch/select inside the callback of a context.select',
);
assert(
T != dynamic,
'''
Tried to call Provider.of<dynamic>. This is likely a mistake and is therefore
unsupported.
If you want to expose a variable that can be anything, consider changing
`dynamic` to `Object` instead.
''',
);
_InheritedProviderScopeElement<T> inheritedElement;
if (context.widget is _InheritedProviderScope<T>) {
// An InheritedProvider<T>'s update tries to obtain a parent provider of
// the same type.
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;
}
...下面省略debugCheckInvalidValueType方法
}
尝试翻译下,向上查找最近的一个使用Provider植入的T类型的value,简单来说就是顺着widget数查找最近的数据类型是T的数据,并返回这个数据,通常情况下,我们想要共享数据,会把数据存放在InheritedWidget
中,因为Flutter 开发中,程序员只能拿到Widget
,通常不会直接操作Element
,但Element
才是真正决定视图显示的,所以,Element
通过持有Widget
来间接操作数据,具体原理可以参考这篇文章。调用Provider.of<T>(context)
时候有个listen
参数,默认是true
,会调用dependOnInheritedElement
,它需要一个_inheritedElementOf
参数,这里会访问当前节点的parent:context.visitAncestorElements
,前提是当前widget
是_InheritedProviderScope
类型的,也就是数据节点,_InheritedProviderScope
我们第一次提到是在说createElement
方法的时候,继续看getElementForInheritedWidgetOfExactType
,已经来到核心代码了
InheritedElement getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
return ancestor;
}
从_inheritedWidgets
取出Key为泛型T的对象的数据,那我们看看是在哪里存储的吧
class InheritedElement extends ProxyElement {
/// Creates an element that uses the given widget as its configuration.
InheritedElement(InheritedWidget widget) : super(widget);
@override
InheritedWidget get widget => super.widget as InheritedWidget;
final Map<Element, Object> _dependents = HashMap<Element, Object>();
@override
void _updateInheritance() {
assert(_active);
final Map<Type, InheritedElement> incomingWidgets = _parent?._inheritedWidgets;
if (incomingWidgets != null)
_inheritedWidgets = HashMap<Type, InheritedElement>.from(incomingWidgets);
else
_inheritedWidgets = HashMap<Type, InheritedElement>();
_inheritedWidgets[widget.runtimeType] = this;
}
下面是Element类的
void mount(Element parent, dynamic newSlot) {
assert(_debugLifecycleState == _ElementLifecycle.initial);
assert(widget != null);
assert(_parent == null);
assert(parent == null || parent._debugLifecycleState == _ElementLifecycle.active);
assert(slot == null);
assert(depth == null);
assert(!_active);
_parent = parent;
_slot = newSlot;
_depth = _parent != null ? _parent.depth + 1 : 1;
_active = true;
if (parent != null) // Only assign ownership if the parent is non-null
_owner = parent.owner;
final Key key = widget.key;
if (key is GlobalKey) {
key._register(this);
}
_updateInheritance();
assert(() {
_debugLifecycleState = _ElementLifecycle.active;
return true;
}());
void activate() {
assert(_debugLifecycleState == _ElementLifecycle.inactive);
assert(widget != null);
assert(owner != null);
assert(depth != null);
assert(!_active);
final bool hadDependencies = (_dependencies != null && _dependencies.isNotEmpty) || _hadUnsatisfiedDependencies;
_active = true;
// We unregistered our dependencies in deactivate, but never cleared the list.
// Since we're going to be reused, let's clear our list now.
_dependencies?.clear();
_hadUnsatisfiedDependencies = false;
_updateInheritance();
assert(() {
_debugLifecycleState = _ElementLifecycle.active;
return true;
}());
if (_dirty)
owner.scheduleBuildFor(this);
if (hadDependencies)
didChangeDependencies();
}
}
说明在mount
和activate
时候都会用,因为子类InheritedElement
重写了_updateInheritance
方法,所以当系统调用mount
或者activate
方法的时候,自然来到了InheritedElement
类的实现,至于这里系统什么时机调用mount
我们还是先mark下。这里有一个需要特别注意的,_inheritedWidgets
这个是定义在Element
类里的字典,但是字典的Key是泛型,Value是InheritedElement
Map<Type, InheritedElement> _inheritedWidgets;
在存储的时候,
_inheritedWidgets[widget.runtimeType] = this;
把自己存在了父类的_inheritedWidgets
中,但如果父类对象已经存储了T类型的InheritedElement
,那就直接复用这个,如果没有就创建它,简单说就是,获取parent值,并注册自身。初始化的时候将InheritedElement
类的对象存储在Element
类的_inheritedWidgets
中,这样在获取的时候,就可以通过parent .getElementForInheritedWidgetOfExactType
拿到,通过调试代码,我们发现_InheritedProviderScope
没有用到,因为这些节点并不是_InheritedProviderScopeElement
类型的,context
类型是SingleChildStatelessElement
,context.widget
的类型是Consumer<T>
context
所以,不管是否是
_InheritedProviderScopeElement
节点,都可以拿到对应的inheritedElement
节点,冥冥之中,我们似乎感觉,一直被系统支配,汇总下我们的问题:
1 我们在使用
ChangeNotifierProvider
的时候,最终是包装成_Delegate
的子类_CreateInheritedProvider
,然而createElement
是谁调的
2 分析Consumer
,最终在调用builder
的时候使用到了系统回调context
,context
的类型为什么是SingleChildStatelessElement
3 在给builder
传递参数的时候,使用的Provider.of<T>(context)
最终是使用Element
类的_inheritedWidgets
存储的InheritedElement
,最终应用层拿到的T实际是inheritedElement.value
,那InheritedElement
和T
又是如何建立关系的
这一切的答案都在Element
中,由于篇幅有限,我们带着这些问题,通过代码调试,在下一篇来一探究竟
网友评论