接前一篇文章 Flutter状态管理Provider(一) 简易使用
过程分析
1.State之setState
我们debug前一篇示例的代码。
///----------------->
///进入setState
void setState(VoidCallback fn) {
final Object? result = fn() as dynamic;
_element!.markNeedsBuild();///这一步Element
}
///----------------->
///进入Element
/// Marks the element as dirty and adds it to the global list of widgets to
/// rebuild in the next frame.
///将element标记位dirty,并加入到全局列表,用于下一帧rebuild
///
/// 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.最好仅在帧开始之前标记,非build过程中
//
void markNeedsBuild() {
if (!_active) return;
if (dirty) return;
_dirty = true;
owner.scheduleBuildFor(this); ///BuildOwner
}
///----------------->
///BuildOwner.scheduleBuildFor:
/// Adds an element to the dirty elements list.so that it will be rebuilt
/// when [WidgetsBinding.drawFrame] calls [buildScope].
///把element加入到dirty列表,这样drawFrame时就能rebuild 这个 dirty element
void scheduleBuildFor(Element element) {
if (element._inDirtyList) {
_dirtyElementsNeedsResorting = true;
return;
};
if (!_scheduledFlushDirtyElements && onBuildScheduled != null) {
_scheduledFlushDirtyElements = true;
onBuildScheduled();
}
_dirtyElements.add(element);
element._inDirtyList = true;
}
重新构建的调用栈是这样的。
首先:告诉系统需要重新构建
onBuildScheduled()
最终调用 SchedulerBinding.scheduleFrame()
.
告诉系统,等下次合适的机会,调用PlatformDispatcher._drawFrame
来重新构建。
那这个机会什么时候来?在Android上就是等Choreographer.FrameCallback.doFrame
,即Vsync信号.
然后:Vsync到来后的重新构建
PlatformDispatcher._drawFrame
最终会调用我们XXWidgetState.build()
更多细节可以参考
2.InheritedWidget
setState 通过 Element.markNeedsBuild()
,让系统在合适的机会rebuild。
接下来是InheritedWidget,关注两个问题:
- 如何共享数据?
- 如何控制rebuild?
2.1.如何共享数据
首先要从InheritedWidget的使用入手
////CountProvider继承InheritedWidget,保存我们的数据
class CountProvider extends InheritedWidget {
final int count;
...
}
//拿到CountProvider实例
CountProvider provider1 = BuildContext.getElementForInheritedWidgetOfExactType<CountProvider>().widget;
var count=provider1.count;
先来看BuildContext对象
/// [BuildContext] objects are actually [Element] objects. The [BuildContext]
/// interface is used to discourage direct manipulation of [Element] objects.
///BuildContext对象 其实就是Element对象。BuildContext接口是用来阻止对Element对象的直接访问。显而易见,Element是实现细节,系统不希望我们直接操作Element
abstract class BuildContext {
Widget get widget;
BuildOwner? get owner;
RenderObject? findRenderObject();
InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>();
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object? aspect });
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect });
}
InheritedElement是啥?我们进入到InheritedWidget。
abstract class InheritedWidget extends ProxyWidget {
const InheritedWidget({ Key key, Widget child })
: super(key: key, child: child);
///对应Element是InheritedElement
@override
InheritedElement createElement() => InheritedElement(this);
///当InheritedWidget rebuilt时,不一定要rebuilt依赖它的widget,这取决于你的updateShouldNotify方法。
@protected
bool updateShouldNotify(covariant InheritedWidget oldWidget);
}
我继续回到BuildContext.getElementForInheritedWidgetOfExactType
即Element
中
abstract class Element implements BuildContext {
Map<Type, InheritedElement> _inheritedWidgets;
@override
InheritedElement getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
///key为T的Type,从_inheritedWidgets中获取 InheritedElement
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[T];
return ancestor;
}
}
///子Element共享其parent的_inheritedWidgets。这个很关键。
void _updateInheritance() {
...
_inheritedWidgets = _parent?._inheritedWidgets;
}
///而_updateInheritance()是在mount()或者active()中调用
///mount()是首次把element添加到element Tree,然后 element是active状态
///active()是把deactivate element ,重新标记为active状态
///总之是从无到有或者从不可见到可见。
@mustCallSuper
void mount(Element parent, dynamic newSlot) {
...
_active = true;
_updateInheritance();
}
@mustCallSuper
void activate() {
...
_dependencies?.clear();
_updateInheritance();
}
InheritedElement 继承自Element。那它的_updateInheritance方法是怎样的? 把自身加了进去。这样:
- 下一层Element可以拿到上面的InheritedWidget
- 但上一层Element无法拿到下面的InheritedWidget 回过头来看,其实也挺简单的。当前Element会继承(保存)parent的InheritedElement。所以不管Element 与InheritedElement相隔多少层,只要是childElement,都是可以传递过来的。
class InheritedElement{
@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;
}
}
2.2.如何控制rebuild
2.2.1 Element与InheritedElement互相引用
现在我们进入到Element.dependOnInheritedWidgetOfExactType
abstract class Element implements BuildContext {
@override
T dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object aspect}) {
final InheritedElement ancestor = _inheritedWidgets[T];
///建立依赖,双向引用
return dependOnInheritedElement(ancestor, aspect: aspect);
}
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect }) {
_dependencies ??= HashSet<InheritedElement>();
///Element与InheritedElement互相引用
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
}
class InheritedElement{
@protected
void updateDependencies(Element dependent, Object aspect) {
setDependencies(dependent, null);
}
@protected
void setDependencies(Element dependent, Object value) {
_dependents[dependent] = value;
}
}
2.2.2 Element.rebuild执行过程
setState()
后会执行Element.rebuild()
,继而调用performRebuild
(基类抽象方法,需要子类实现)。继而来看我们关心的Element的子类
abstract class Element implements BuildContext {
void rebuild() {
...
performRebuild();
...
}
///基类抽象方法,需要子类实现。
@protected
void performRebuild();
}
classDiagram
Element <|-- ComponentElement
ComponentElement <|-- StatefulElement
ComponentElement <|-- ProxyElement
ProxyElement <|-- InheritedElement
我们以上篇自定义的ChangeNotifierProvider为例来讲InheritedElement。
class ChangeNotifierProvider extends StatefulWidget {
final Widget child;
final CountModel model;
...
}
class _ChangeNotifierProviderState extends State<ChangeNotifierProvider> {
..
@override
Widget build(BuildContext context) {
return CountProvider( model: widget.model, child: widget.child);
}
}
class CountProvider extends InheritedWidget {
final CountModel model;
...
static CountModel of(BuildContext context, bool depend) {
var provider = depend
? context.dependOnInheritedWidgetOfExactType<CountProvider>()
: context.getElementForInheritedWidgetOfExactType<CountProvider>()?.widget;
return (provider as CountProvider).model;
}
@override
bool updateShouldNotify(CountProvider old) { return true;}
}
我们进入ComponentElement
///此时的ComponentElement与ChangeNotifierProvider对应
abstract class ComponentElement extends Element{
@override
void performRebuild() {
///调用_ChangeNotifierProviderState.build(),built为新生成的CountProvider
Widget built= build();
_child = updateChild(_child, built, slot);
}
}
@protected
Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
///newWidget为null,则让child失活不可见,并不会清除。
if (newWidget == null) {
if (child != null)
deactivateChild(child);
return null;
}
if (child != null) {
///新老CountProvider是同一个对象,处理下slot,及可见性
///这个地方也告诉我们CountProvider的child每次都new一个对象,也会全部rebuilt
if (child.widget == newWidget) {
if (child.slot != newSlot)
updateSlotForChild(child, newSlot);
return child;
}
if (Widget.canUpdate(child.widget, newWidget)) {
if (child.slot != newSlot)
updateSlotForChild(child, newSlot);
///此时 child是InheritedElement,newWidget是我们新构建CountProvider
///*只有这里才会进入我们的InheritedElement
child.update(newWidget);
return child;
}
deactivateChild(child);
}
return inflateWidget(newWidget, newSlot);
}
接着上述的child.update(newWidget)
,InheritedElement
结合ProxyElement
一起看。
class ProxyElement extends ComponentElement{
@override
void update(ProxyWidget newWidget) {
final ProxyWidget oldWidget = widget;
super.update(newWidget);
updated(oldWidget);
_dirty = true;
rebuild();
}
@protected
void updated(covariant ProxyWidget oldWidget) {
notifyClients(oldWidget);
}
}
InheritedElement重载了updated()方法,额外增加updateShouldNotify判断,减少不必要重建。同时实现了notifyClients(),通知给引用InheritedElement的Element。
class InheritedElement extends ProxyElement{
@override
void updated(InheritedWidget oldWidget) {
if (widget.updateShouldNotify(oldWidget))
super.updated(oldWidget);
}
@override
void notifyClients(InheritedWidget oldWidget) {
///_dependents中保存的都是
///通过dependOnInheritedWidgetOfExactType产生依赖的子孙Element
for (Element dependent in _dependents.keys) {
notifyDependent(oldWidget, dependent);
}
}
@protected
void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {
///最终调用dependent的markNeedsBuild();
dependent.didChangeDependencies();
}
}
abstract Element{
@mustCallSuper
void didChangeDependencies() {
...
markNeedsBuild();
}
}
到这里我们算是把方法的调用栈说明白了。也对InheritedWidget的内部原理大概有了认识。 其实就是观察者模式:注册监听,通知更新的逻辑。还有更多细节还在继续学习中。
这些内容,足够让我们进入到Provider的使用过程中。
3.ChangeNotifierProvider
这个地方我们挑常用的ChangeNotifierProvider分析 回顾代码
class CountModel extends ChangeNotifier {
int count;
void increment() {
count++;
notifyListeners();
}
}
class _ProviderDemoWidget4State extends State<ProviderDemoWidget4> {
CountModel _countModel = CountModel(0);
@override
Widget build(BuildContext context) {
return Scaffold(
...
body: ChangeNotifierProvider.value(
value: _countModel,
...
child: Column(
children: <Widget>[
Consumer<CountModel>(
builder: (contextC, model, child) {
return Text("计数:${model.count}(有依赖情况)");
},
),
Builder(builder: (context2) {
return Text( "计数:${Provider.of<CountModel>(context2, listen: false).count}(无依赖情况)");
}),
RaisedButton(child: Text("increment"),onPressed: () => _countModel.increment()),
],
),
),
);
}
}
InheritedProvider类图
ChangeNotifierProvider最终继承InheritedProvider。InheritedProvider是整个Provider的中心。它的关键组件: _ValueInheritedProvider,_InheritedProviderScope.
_Delegate(_ValueInheritedProvider)与 _DelegateState
InheritedProvider将以下功能委托给_ValueInheritedProvider:
- 数据T赋值,
- 监听设置,
- shouldUpdate
_InheritedProviderScope 与 _InheritedProviderScopeElement
_InheritedProviderScopeElement
继承InteritedElement
。_InheritedProviderScope
继承InheritedWidget
。
ChangeNotifierProvider初始化过程
通过前一个篇章的分析,我们知道ComponentElement
的初始/重新构建是在performBuild()
中.
_InheritedProviderScopeElement
也不例外,其中的逻辑大抵是与InheritedElement
相近的。
接着看子Element的构建,发现model的获取有两种方式Consumer和Provider。
Consumer<CountModel>(
builder: (contextC, model, child) {
return Text("计数:${model.count}(有依赖情况)");
},),
Builder(builder: (context2) {
return Text(
"计数:${Provider.of<CountModel>(context2, listen: false).count}(无依赖情况)");
}),
Consumer里面代码相对简单些,可以理解成把Provider.of(context)封装了了,默认listen为true。Consumer即消费,那肯定是要添加依赖关系的,响应数据变化。 Provider继承了InheritedProvider。 提供了.of方法,与我们所写的Provider大致是相同的。
value & _startListening
先看下继承和关联关系
classDiagram
InheritedProvider <|-- Provider
Provider .. Consumer
ListenableProvider <|-- ChangeNotifierProvider
InheritedProvider <|-- ListenableProvider
class InheritedProvider{
+_ValueInheritedProvider _delegate
}
InheritedProvider .. _ValueInheritedProvider
_ValueInheritedProvider .. _ValueInheritedProviderState
从ChangeNotifierProvider.value
构造方法往上追溯可以得知:
ListenableProvider具有静态函数_startListening
class ListenableProvider{
static VoidCallback _startListening(InheritedContext e,Listenable? value) {
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
}
最终我们的 value T
和 _startListening
都给了_ValueInheritedProvider
。
class _ValueInheritedProvider<T> extends _Delegate<T> {
final T value;
///上面的流程没有传递这个值
final UpdateShouldNotify<T>? _updateShouldNotify;
final StartListening<T>? startListening;
@override
_ValueInheritedProviderState<T> createState() {
return _ValueInheritedProviderState<T>();
}
}
class _ValueInheritedProviderState<T>
extends _DelegateState<T, _ValueInheritedProvider<T>> {
VoidCallback? _removeListener;
///此方法什么时候调用?
@override
T get value {
_removeListener ??= delegate.startListening?.call(element!, delegate.value);
return delegate.value;
}
@override
bool willUpdateDelegate(_ValueInheritedProvider<T> newDelegate) {
bool shouldNotify = newDelegate.value != delegate.value;
if (shouldNotify && _removeListener != null) {
_removeListener!();
_removeListener = null;
}
return shouldNotify;
}
...
_startListening
在 T get value
中调用。
那T get value
什么时候调用? 首次调用 Provider.of()时。
class Consumer<T> extends SingleChildStatelessWidget {
@override
Widget buildWithChild(BuildContext context, Widget? child) {
return builder(
context,
Provider.of<T>(context),
child,
);
}
}
class Provider extends InheritedProvider<T>{
static T of<T>(BuildContext context, {bool listen = true}) {
....
return inheritedElement.value;
}
}
class _InheritedProviderScopeElement{
@override
T get value => _delegateState.value;
}
总之,addListener首次是在Element mount过程中调用的。
ChangeNotifier.notifyListeners过程
notifyListeners()
最终调用到_InheritedProviderScopeElement.markNeedsNotifyDependents
class CountModel extends ChangeNotifier {
int count;
CountModel(this.count);
void increment() {
count++;
notifyListeners();
}
}
我们进入到 ChangeNotifier.notifyListeners(),遍历并且执行注册的listener。
class ChangeNotifier{
void notifyListeners() {
final List<VoidCallback> localListeners = List<VoidCallback>.from(_listeners);
for (VoidCallback listener in localListeners) {
if (_listeners.contains(listener)) listener();
}
}
}
}
进入下面
class _InheritedProviderScopeElement{
@override
void markNeedsNotifyDependents() {
if (!_isNotifyDependentsEnabled) return;
markNeedsBuild();
_shouldNotifyDependents = true;
}
}
接下来就是_InheritedProviderScopeElement.performRebuild()
。
回顾InheritedElement,是调用updateChild方法-->updated-->notifyClients-->notifyDependent。
重载了build()方法,notifyClients()放到到super.build()前。notifyClients的逻辑就是InheritedElement定义的。dependent的刷新ok了。
class _InheritedProviderScopeElement
@override
Widget build() {
...
_delegateState.build(_isBuildFromExternalSources);
if (_shouldNotifyDependents) {
_shouldNotifyDependents = false;
notifyClients(widget);
}
return super.build();
}
InheritedElement的特性就在于不会层层update它底下的element,而只是调用notifyClients,update有依赖的element。
从代码的分析来看,我们的视角始终是围绕着Element, Widget用来构建/更新Element。
StreamProvider
InheritedProvider的众多子类分成了以下分支:
- Provider:需要手动管理监听
- ListenableProvider:不需要手动管理监听,但泛型参数T要继承Listenable。
- ChangeNotifierProvider
- DeferredInheritedProvider
- ValueListenableProvider
- FutureProvider
- StreamProvider DeferredInheritedProvider,相对ListenableProviderT本身具有监听功能。Deferred*不直接监听T,但T是如下形式:Stream,Future,ValueListenable。
Flutter基于Stream,做了一套状态管理的StreamBuilder。 ChangeNotifierProvider已经可以满足现在的使用场景,暂时还没用到StreamProvider。