写点什么

源码篇:Flutter Provider 的另一面(万字图文 + 插件)

用户头像
小呆呆666
关注
发布于: 2021 年 06 月 30 日

前言

阅读此文的彦祖,亦菲们,附送一枚 Provider 模板代码生成插件!


我为啥要写这个插件呢?


此事说来话短,我这不准备写解析 Provider 源码的文章,肯定要写这框架的使用样例啊,然后再哔哔源码呀!在写 demo 样例的时候,新建那俩三个文件、文件夹和必写的模板代码,这让我感到很方啊,这不耽误我时间嘛!然后就撸了这个插件,相对而言,多花了几百倍的时间。。。


希望这个插件,能减轻使用 Provider 小伙们的一点工作量;插件里面的模板代码是经过我深思熟虑过的,如果各位靓仔有更好的模板代码,请在评论里贴出来,我觉得合理的话,会加入到插件里。


关于 Provider 的源码,如果对设计模式或面向接口编程不熟悉的话,看起来是相当懵逼的,基本就是:懵逼树上懵逼果,懵逼树下你和我;Provider 源码使用了大量的抽象类,调用父类构造函数,继承实现断言,很多关键的函数调用,点进去都是抽象类,必须返回好几层去看看这个抽象类的实现类是什么,看的十分头大!这里面有很多设计模式的痕迹:观察者模式、策略模式、外观模式、命令模式、访问者模式、模板模式、迭代器模式、、、


我会竭尽所能的将总体流程说清楚,相关晦涩流程会结合图文,并给出相应小 demo 演示


ε=(´ο`*)))唉,这篇文章写完,我感觉整个人都被掏空了。。。



不管你用或不用 Provider,我相信在你读完本文的刷新机制栏目,大概率会对该框架中闪耀的智慧,感到由衷的赞叹!

使用

老规矩,说原理之前,先来看下使用

Provider 的使用,和我前俩篇写的 Handler 和 ThreadLocal 使用有一些区别

Provider 是一个状态管理框架,写它的使用可能会占较多篇幅,所以文章整体篇幅也会较长,请见谅。。。

我实在不想分篇幅水赞啊,而且也是为了方便大家可以在一篇文章里面查阅相关知识(请结合掘金旁边的大纲食用),也方便我随时修改优化文章内容。。。

插件

  • 插件 github:provider_template

  • 使用中碰见什么 bug,希望大家能及时给我提 issue

  • 插件可以进入 Android Studio 的 Setting 里面,选择 Plugins,然后搜索 flutter provider,第一个,看图上红框标定的就是了,点击 install 安装即可



  • 来下看使用效果图



  • 如果你不喜欢这种命名方式,这里提供修改入口;也支持了持久化

  • 大家按需修改吧



  • Alt + Enter : 可以选择包裹 Widget,有三种可选(Consumer、Selector、ChangeNotifierProvider),一键生成麻烦,重复且使用频率很高的 Widget!



  • 快捷代码片段提示:我自己写了三个,如果老哥们还有其它的骚操作,需要各位提 PR 啊

  • 在这个文件里面添加就行了,大家可以参照写法:provider_template

  • 输入 provider 前缀便有提示


初始写法

在写 Provider 的 demo 实例的时候,是按照下面这种写法的,毕竟下面这种写法,是非常正统且常见的一种写


ChangeNotifierProvider 中为什么用 builder?而不用 child?


  • Provider.of<T>(context, listen: false)中的 context,必须是 ChangeNotifierProvider 或其子 Widget 的

  • 使用 ProEasyCounterPage 的 context,会发现无法找到 ProEasyCounterProvider 的情况,导致无法触发 increment()方法

  • 原理是什么?看完文章,你就造了


class ProEasyCounterPage extends StatelessWidget {  @override  Widget build(BuildContext context) {    return ChangeNotifierProvider(      create: (BuildContext context) => ProEasyCounterProvider(),      builder: (context, child) {        return buildPage(context);      },    );  }
Widget buildPage(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Provider-Easy范例')), body: Center( child: Consumer<ProEasyCounterProvider>( builder: (context, provider, child) { return Text( '点击了 ${provider.count} 次', style: TextStyle(fontSize: 30.0), ); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () { return Provider.of<ProEasyCounterProvider>(context, listen: false) .increment(); }, child: Icon(Icons.add), ), ); }}
class ProEasyCounterProvider extends ChangeNotifier { int count = 0;
void increment() { count++; notifyListeners(); }}
复制代码


这地方有个让我很难受的地方,就是 Provider.of 这个实在是太长了,但是我如果不使用 Provider.of,就需要把 Scaffold 整体包裹在 Consumer 里面,这样可以直接拿到 provider 变量使用,,,但是这样的话,Consumer 包裹的模块就有点太大了。。。


而且 Provider.of 这地方还只是使用了模块内 Provider,还不是获取全局的 Provider,使用频率肯定很高,都这么写而且这么长,想想就头皮发麻,我方了呀。。。


优化写法

上面那个 Provider.of 写法,让我巨难受:走在回去的路上想,有什么方法可以优化呢?洗澡的时候想,有什么方法可以优化呢?

我转念一想,我这地方只是写个使用 demo,我特么有必要这么纠结吗?!

但是,我就是纠结的一批啊,一定有什么方法可以优化!(魔改框架? ...石乐志吧我)

突然灵光一闪!我!看到了光!盖亚!

既然 ChangeNotifierProvider 里面 create 参数,是接受了我实例化的 ChangeNotifier 对象,然后它内部存了起来,然后在 Consume 里面的 builder 方法里面分发给我,那我自己是不是也可把 ChangeNotifier 对象存起来!


  • 突然间醍醐灌顶,思路就突破了,然后就可以愉快的在这上面玩耍了


class ProEasyCounterPage extends StatelessWidget {  final provider = ProEasyCounterProvider();
@override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (BuildContext context) => provider, child: _buildPage(), ); }
Widget _buildPage() { return Scaffold( appBar: AppBar(title: Text('Provider-Easy范例')), body: Center( child: Consumer<ProEasyCounterProvider>( builder: (context, provider, child) { return Text('点击了 ${provider.count} 次', style: TextStyle(fontSize: 30.0)); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () => provider.increment(), child: Icon(Icons.add), ), ); }}


class ProEasyCounterProvider extends ChangeNotifier { int count = 0;
void increment() { count++; notifyListeners(); }}
复制代码


Provider.of<ProEasyCounterProvider>(context, listen: false).increment() 直接变成 provider.increment()


一个模块里面,会有很多地方用到 provider,这样一改,瞬间轻松很多,而且还不需要传 context 了。。。


在这上面我们还能骚!还能简化!


  • 因为这里我们直接使用我们自己储存起来 provider,所以可以进一步简化

  • Consumer 进行了简化,builder 方法里面参数,大部分情况不需要了

  • 我甚至都想把泛型去掉;看了下源码,应该很难去掉,泛型在框架内部起到了至关重要的作用


//原版Consumer<ProEasyCounterProvider>(builder: (context, provider, child) {    return Text(        '点击了 ${provider.count} 次',        style: TextStyle(fontSize: 30.0),    );   }),
//简化Consumer<ProEasyCounterProvider>(builder: (_, __, ___) { return Text( '点击了 ${provider.count} 次', style: TextStyle(fontSize: 30.0), );}),
复制代码


浏览了 Provider 内部的源码后,发现:按照上面这样写是完全没问题!会一定程度上提升效率!


凎!可以把插件和 demo 代码全改了!搞起!

插件生成代码

插件生成代码分为俩个模式:Default 和 High

默认模式有俩个文件(Default):view、provider

高级模式有三个文件(High):view、provider、state

大家都是用 Flutter 的老手,对这种结构应该非常了解,state 层是把数据层独立出来维护

在非常复杂的提交界面,state 层我甚至还会分出:跳转(jump)、提交(submit)、展示(show)这三种结构;没办法,一个模块搞了上百个变量,不这样分,太难维护了


default:默认模式下的模板代码


  • view


import 'package:flutter/material.dart';import 'package:provider/provider.dart';
import 'provider.dart';
class CounterPage extends StatelessWidget { final provider = CounterProvider();
@override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (BuildContext context) => provider, child: Container(), ); }}
复制代码


  • provider


import 'package:flutter/material.dart';
class CounterProvider extends ChangeNotifier {
}
复制代码


High:高级模式下的模板代码


  • view


import 'package:flutter/material.dart';import 'package:provider/provider.dart';
import 'provider.dart';
class CounterPage extends StatelessWidget { final provider = CounterProvider();
@override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (BuildContext context) => provider, child: Container(), ); }}
复制代码


  • provider


import 'package:flutter/material.dart';
import 'state.dart';
class CounterProvider extends ChangeNotifier { final state = CounterState();}
复制代码


  • state


class CounterState {
CounterState() { // init some variables }}
复制代码

前置知识

下面就是 Provider 的源码分析内容了,如果大家赶时间,可以点个赞(方便日后查阅,滑稽.jpg),回头等有时间,再静下心来慢慢看;我怕你快餐式阅读,读到刷新机制那块,会直接骂街,这写的啥玩意???

Provider 的刷新机制,相关流程相当之绕,我已经竭尽全力,精简了无数我们不需要关注的代码,然后一步步带着你的思路去走一遍正确的流程,相关类还给了很多说明,但是架不住源码流程山路十八弯,绕的一比啊!你如果不用心去看,去体会,会相当烦躁。。。

我已经帮大家熬过最蛋筒的部分,相关绕的流程画了详细的图示,我已经努力了;如果你想知道 Provider 内部运转机制,现在就需要你努力了!

ChangeNotifier 的单独使用

ValueListenableBuilder 和 ValueNotifier 可以配套使用,ValueListenableBuilder 内部也是一个 StatefulWidget,代码很简单,感兴趣的可以自己查看

这个暂且不表,这边就搞最原始的 ChangeNotifier 的使用


大家肯定在 Provider 都写过继承 ChangeNotifier 的代码,而且写的非常多,但是大家知道怎么单独使用 ChangeNotifier,以达到控制界面变化的效果吗?


我搜了很多怎么单独使用 ChangeNotifier 的文章,但是基本都是写配合 ChangeNotifierProvider 在 Provider 中使用的,我佛了呀,搜到寥寥无几的文章,也没说清楚,怎么单独使用;我想这玩意是不是有个单独 XxxWidgetBuild 配合使用?但是!我怎么都找不到,气抖冷!


我突然想到,TextField 控件中的 TextEditingController 用到了 ChangeNotifier,总不可能 TextField 还用 Provider 吧!我在源码里面一通翻,各种 super,abstract,私有变量,看的头皮发麻,最后终于找到了关键代码,搞清楚 TextField 是怎么使用 ChangeNotifier 的了,为什么每次改变 TextEditingController 的 text 值,然后在 TextField 数据框里的数据也及时改变了,其实最后还是用到 setState


TextField 中的流程代码不贴了,如果贴出来,会相当占篇幅:我下面会写一个颗粒度最小 ChangeNotifier 的单独使用 demo


  • TextEditingController 实际是继承了 ValueNotifier,来看下 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 实际是对 ChangeNotifier 的封装

这里影响不大,我们还是使用 ChangeNotifier,来写一个类似 TextField 中的控制器效果,每当控制器中的数值改变,其控件内容就自动更新


  • 先使用 ChangeNotifier 搞一个控制器


class TestNotifierController extends ChangeNotifier {  String _value = '0';
String get value => _value;
set value(String newValue) { if (_value == newValue) return; _value = newValue; notifyListeners(); }}
复制代码


  • 搭配这个控制器的 Widget

  • OK,这样就搞定了,改变控制器的数据,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(() {}); }}
复制代码


  • 来看下怎么使用这个控件

  • 使用代码已经非常简单了:onPressed 改变了控制器数值内容,TestNotifierWidget 控件会自动刷新


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: () { controller.value = '数值变化:${(++count).toString()}'; }, child: Icon(Icons.add), ), ); }}
复制代码


  • 来看下效果图


Function Call()

这里说个小知识点,源码里面大量使用了这个技巧,网上搜了下,很少提到这个的,这边记一笔


每个 Function 都有个 Call()方法


  • 下面俩种方式调用是等同的,都能调用 test 方法


void main(){    test();
test.call();}
void test(){ print('test');}
复制代码


你可能想,这有什么用,我还多写一个 .call ?

来看下一个小范例,就知道这个东西能帮我们简化很多代码


  • 平时封装带有 CallBack 回调 Widget

  • 这边写了俩个自定义的点击回调判断操作

  • 如果不做判空操作,外部未实现这个 Function,点击事件会报空异常


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(), ); }}
复制代码


  • 使用 .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 的刷新机制是非常重要的,只要把 Provider 的刷新机制搞清楚,这个框架在你面前,将不在神秘!

实际上,大家只要看到 ChangeNotifier 的应用,那肯定知道,这就是个观察者模式,但是问题是:它的监听在何处添加?添加的监听逻辑是否有完整的初始化链路?监听逻辑是什么?为什么触发监听逻辑,能导致相应控件刷新?


  • 上面初始化的完整链路看的真是有点蛋痛

  • 源码东一榔锤西一棒的,而且还用了大量了抽象类,想直接定位逻辑,那是不可能的,你必须找到实现类赋值的地方,才能明白内部运转

  • 不搞清楚完整初始化链路,内心就相当于膈应,明知道他肯定初始化了,却不知道他在哪初始化的,就很难受

  • 我下面将相关流程理了一遍,希望对大家有所帮助

  • 要读懂 Provider,必须要有个前提,明白什么观察者模式:观察者模式其实很简单,简单描述下

  • 定义个 List 类型,泛型为一个抽象类,初始化这个 List

  • 然后给这个 List,add 这个抽象类的实现类实例

  • 某个合适时候,遍历这个 List 所有实例,触发所有实例的某个方法

  • 如果将这个思想和反射注解结合在一起,就能大大拓宽它的使用面,例如 android 里的 EventBus。。。

总流程

继承 ChangeNotifier 的类,是通过 ChangeNotifierProvider 传入到 Provider 内部,很明显 ChangeNotifierProvider 这个类很重要,基本可以算是框架的主入口


这边梳理下 ChangeNotifierProvider 回溯的总流程,其它的旁枝末节,暂时不贴代码,这个往上回溯的过程,实例了一个很重要的上下文类,很多关键的类初始化都和这个上下文类有关系,先来回溯下这个重要的流程!


  • ChangeNotifierProvider

  • 这地方有个_dispose 回调,是定义好的,内部逻辑是回收 ChangeNotifier 实例

  • 这里将该方法赋值给了他的父类 ListenableProvider,然后一层层往上回溯


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();  }}
复制代码


  • ListenableProvider

  • 这地方有个_startListening 回调,这个方法极其重要


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);  }}
复制代码


  • InheritedProvider

  • 这个类就是逻辑的纠缠点了:我省略了大量和主流程无关的代码,不然会十分影响你的关注点,会很难受

  • 这里就不需要看他的父类了,他的父类是 SingleChildStatelessWidget,这个类是对 StatelessWidget 类的一个封装,能稍微优化下嵌套问题,无关紧要

  • 需要看下 buildWithChild(看成 StatelessWidget 的 build 方法就行了)方法里面的_InheritedProviderScope 类,来看下他的源码


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!, ); }}
复制代码


  • _InheritedProviderScope

  • 这里是继承了 InheritedWidget,里面重写 createElement 方法,在构建 Widget 的时候,这个方法是肯定会被调用的!

  • 马上就要到最重要的类了,就是 createElement 中实例化的_InheritedProviderScopeElement 类!


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); }}
复制代码


  • _InheritedProviderScopeElement:实现方法里面的逻辑全省略了,逻辑太多,看着头晕

  • 先说明下,这个类是极其极其重要的!大家可以看下他实现了一个什么抽象类:InheritedContext!

  • InheritedContext 继承了 BuildContext,也就是说,这里作者实现了 BuildContext 所有抽象方法

  • 是的,BuildContext 也是个抽象类,我们可以去实现多个不同实现类

  • 内部系统只需要特定的周期去触发相应方法,就可以了

  • 你可以在相应的方法里面实现自己的逻辑,大大的扩展了逻辑,怎么说呢?有点策略模式味道,可以动态替换实现类

  • _InheritedProviderScopeElement 算是实现了:InheritedContext 和 BuildContext;BuildContext 中有很多方法是和控件生命周期挂钩的,例如热重载触发(reassemble),setState 触发(build、performRebuild)、以及很有意思的强制依赖项组件刷新(markNeedsNotifyDependents:这是 Provider 作者在 InheritedContext 中抽象的方法)。。。


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) { ... }}
复制代码


上面进行了五步的回溯流程,如果不仔细看清楚相关类里面的逻辑,很可能就迷失在 super 方法里。。。

通过上面的五步回溯,我们可以断定一个事实:_InheritedProviderScopeElement(实现 BuildContext) 被实例化了,而且他在初始化的时候被调用了,对应的,其内部相应的周期也能被正常触发!这样之前看源码困扰我的很多问题,就迎刃而解了!


  • 图示

  • 上面回溯的层级过多,还有很多的继承和实现

  • 看了后,脑中可能没啥印象,所以此处画了流程图,可以参照对比


添加监听

整个刷新机制里面有个相当重要的一环,我们从 Create 中传入的类,它内部是怎么处理的?


class ProEasyCounterPage extends StatelessWidget {  final provider = ProEasyCounterProvider();
@override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (BuildContext context) => provider, child: Container(), ); }}
复制代码


就算没看源码,我也能断定传入的 XxxProvider 实例,肯定使用了其本身的 addListener 方法!

但是找这个 addListener 方法,实在让我找自闭了,之前因为没梳理总流程,对其初始化链路不明晰,找到了 addListener 方法,我都十分怀疑,是不是找对了、其它地方是不是还有 addListener 方法;后来没办法,就把 Provider 源码下载下来(之前直接项目里面点 Provider 插件源码看的),全局搜索 addListener 方法,排除所有的测试类中使用的,然后断定我找对了,整个添加监听的链路是通顺的!


下面来整体的带大家过一遍源码


靓仔们,我要开始绕了!!!


流转

  • ChangeNotifierProvider

  • 明确下 Create 是一个 Function,返回继承 ChangeNotifier 类的实例

  • 这里一定要记住 create 这个变量的走向,其中的 T 就是继承 ChangeNotifier 类的关键类

  • 增加了_dispose 方法,传给了父类

  • create 这里 super 给其父类,回溯下父类


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(); }}
复制代码


  • ListenableProvider

  • 此处将 create 实例 super 给了父类

  • 还增加一个_startListening 方法,也同样给了父类


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); }}
复制代码


  • InheritedProvider

  • 这地方和上面总流程不太一样了

  • create、dispose、startListening 传给了_CreateInheritedProvider

  • 需要看下_CreateInheritedProvider


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);
...}
复制代码


  • 流程图示


_CreateInheritedProvider

这地方会进行一个很重要的回溯流程,回溯到_InheritedProviderScopeElement

下次再有需要用到这个类,就直接拿这个类来讲了


  • _CreateInheritedProvider 说明

  • _CreateInheritedProvider 继承了抽象类 _Delegate,实现了其 createState 抽象方法

  • 按理说,主要逻辑肯定在 createState 方法中 _CreateInheritedProviderState 实例中

  • 必须要看下_CreateInheritedProvider 实例,在何处调用 createState 方法,然后才能继续看 _CreateInheritedProviderState 的逻辑


@immutableabstract 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();}
复制代码


  • 这里需要重新回顾下 InheritedProvider 类

  • 这地方做了一个很重要的操作,将_CreateInheritedProvider 实例赋值给 _delegate

  • buildWithChild 方法中_InheritedProviderScope 的 owner 接受了 InheritedProvider 本身的实例

  • 结合这俩个就有戏了,再来看下_InheritedProviderScope 类


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;    ...
@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!, ); }}
复制代码


  • _InheritedProviderScope

  • createElement 方法传入_InheritedProviderScope 本身的实例

  • 关键的在_InheritedProviderScopeElement 类中


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); }}
复制代码


  • _InheritedProviderScopeElement 类,我就直接精简到关键代码了

  • 有没有感觉 InheritedWidget 很像 StatefulWidget,实际他俩最终都是继承 Widget,未对 Widget 的建造者模式那层封装,所以有俩层结构;而 StatelessWidget 将建造者模式那层进行了封装,所以只有一层结构

  • 下面的关键代码看到没! widget.owner._delegate.createState() ... 这地方调用了_CreateInheritedProvider 类的 createState() 方法,安心了

  • performRebuild:该回调会在 setState 或者 build 的时候会触发;此处做了一个判断,只会在第一次 build 的时候触发

  • 这里可以确定_CreateInheritedProvider 类中的 createState 方法一定会被调用;接下来看看其方法里面调用的 _CreateInheritedProviderState 类


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(); }
...}
复制代码


  • 流程图示


_InheritedProviderScopeElement

  • _CreateInheritedProviderState:这个类做了很多事情,很多的主体逻辑的都在此处理

  • 该类代码很多,此处只留下我们需要关注的代码,因为省略了很多代码,从下面的主体代码来看,流程就清楚了:create、startListening、dispose 都有

  • 但是这些变量是依附在 delegate 上的,这个 delegate 是个啥?需要看下继承的抽象类 _DelegateState


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); } }
...}
复制代码


  • _DelegateState

  • delegate 是通过 _InheritedProviderScopeElement 的实例获取到了 owner 然后获取到了 _delegate 变量

  • _delegate 这个变量是在 InheritedProvider 类中的实例化 _CreateInheritedProvider 赋值给他的,不信的话,可以返回去看看

  • 好吉尔绕!!!


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

  • 现在还有个问题,element 这个变量在哪实例化的?怎么大家这么随便用它!就不怕它为空吗?

  • 直接带大家来_InheritedProviderScopeElement 里面看了,上面已经回顾了到这个必定实例化这个上下文类的流程

  • performRebuild 回调中,在调用 createState()方法的时候,给 element 赋值了,element = this

  • 所以在_CreateInheritedProviderState 类中,可以随便使用 element 这个变量,他的值肯定不为空!


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(); }
...}
复制代码


不知道大家对这流程有没有个清晰的印象


  • 来看看这山路十八弯的初始化链路图


_CreateInheritedProviderState

有了上面分析出的 element 和_delegate 不为空的,且 _delegate 能直接访问 _CreateInheritedProvider 这个实例基础,再来看下 _CreateInheritedProviderState 代码


  1. get 流程

  2. 我们传入的 create 会直接赋值给 _value,现在这个 _value,就是我们在外面传进来的那个 XxxProvider 实例了!

  3. 底下也调用了 startListening,说明从外面传进来的这个回调也调用了,将 上下文实例传进来的 XxxProvider 实例 作为入参传进了这个回调中,此处传进来的回调也通过 .call 被调用了!

  4. dispose 流程

  5. 调用 startListening 方法时,该方法会返回一个移除监听 Function

  6. 移除监听的 Function 在 dispose 时被调用,移除给 XxxProvider 添加的监听

  7. 从外部传入的 dispose 方法,也在此处被执行

  8. OK!回收资源的操作在此处都搞定了!


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); } }
...}
复制代码


  • 关键的就是 startListening 回调了,来看下他的逻辑

  • _startListening 在此处 addListener 了!ChangeNotifier 是 Listenable 实现类,姑且把它当成访问者模式也可,所以这个 value 就是我们从外面传进来的 XxxProvider

  • 返回了一个 VoidCallback 的 Function,里面是移除监听逻辑


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); }}
复制代码


还有最后一个问题!!!

需要调用_startListening 方法,必须调用 _CreateInheritedProviderState 类里面的 get value

在哪个初始化入口,使用这个 get value 呢?


  • 这里直接给出结论了,还是在 _InheritedProviderScopeElement 这个上下文类里面

  • reassemble:全局状态的初始化逻辑或热重载的时候被调用

  • _delegateState 首先在 performRebuild 回调中会赋初值

  • 在 reassemble 回调中,_delegateState 调用了 value( _delegateState.value )

  • 所以 get value 肯定会在初始化的时候被调用,上面流程是通顺的


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(); } }
...}
复制代码

总结

上面分析完了添加监听,以及相关的初始化链路和调用链路


  • 可以把流程图整全了,来看看


刷新逻辑

刷新逻辑也是相当之绕啊;本菜比,各种 debug,在 framework 里面各种打断点,终于把流程理通了!我突然感觉自己打通了任督二脉!

作者为了实现这个刷新逻辑,和系统 api 做了大量的交互,相当的精彩!

我会尽力将这个精彩纷呈的操作,展现给大家!

触发

  • ListenableProvider

  • 这地方逻辑很简单,添加了 InheritedContext 这个上下文类中的 markNeedsNotifyDependents 方法

  • 说明,我们在外部使用 notifyListeners() 的时候,一定会触发 InheritedContext 实现类中的 markNeedsNotifyDependents 方法


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); }}
复制代码


  • _InheritedProviderScopeElement: _InheritedProviderScopeElement 是 InheritedContext 的实现类

  • 还是要来这个类看看,只保留了和 markNeedsNotifyDependents 有关的代码

  • markNeedsNotifyDependents 回调作用,总的来说:会将强制依赖于 T 窗口小部件进行重建

  • 说的这么笼统没啥用,下面会全面分析,他是怎么做到让依赖于 T 窗口小部件进行重建的! 我想了下,还是观察者模式的应用。。。


class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)      : super(widget);      ...
@override void markNeedsNotifyDependents() { if (!_isNotifyDependentsEnabled) { return; }
markNeedsBuild(); _shouldNotifyDependents = true; }
...}
复制代码

刷新流程

咱们现在来理一下刷新的流程!


  • markNeedsNotifyDependents

  • 当我们使用 notifyListeners(),就会触发,这个回调

  • 此处调用了 markNeedsBuild(),然后给 _shouldNotifyDependents 设置为 true

  • 必备操作,来看下 markNeedsBuild() 作用


class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)      : super(widget);      bool _shouldNotifyDependents = false;  ...
@override void markNeedsNotifyDependents() { if (!_isNotifyDependentsEnabled) { return; }
markNeedsBuild(); _shouldNotifyDependents = true; }
...}
复制代码


  • markNeedsBuild

  • _InheritedProviderScopeElement 最终继承的还是 Element 抽象类,markNeedsBuild()方法是 Element 中的

  • Element 类是一个实现了 BuildContext 抽象类中抽象方法的抽象类,该类十分重要

  • 这个方法花里胡哨的代码写了一大堆,他最主要的功能:就是会调用 Element 的 performRebuild()方法,然后触发 ComponentElement 的 build()方法,最终触发_InheritedProviderScopeElement 的 build 方法

  • _InheritedProviderScopeElement extends InheritedElement extends ProxyElement extends ComponentElement extends Element


abstract class Element extends DiagnosticableTree implements BuildContext {  ...        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);  }
...}
复制代码


  • build

  • 这里说明下,这个子类调用父类方法,然后父类调用自身方法,是先触发这个子类的重写方法,然后可以通过 super. 的方式去执行父类逻辑

  • 上面给_shouldNotifyDependents 设置为 true,所以 build 内部逻辑会执行 notifyClients(widget)方法

  • 接下来看下 notifyClients(widget)方法


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(); }
...}
复制代码


  • notifyClients:notifyClients()是 InheritedElement 类中的,notifyClients()方法是 ProxyElement 类中的一个抽象方法,InheritedElement 在此处做了一个实现

  • notifyClients()是一个非常非常重要的方法,它内部有个 for 循环,遍历了_dependents 这个 HashMap 类型的所有 key 值, _dependents 的 key 是 Element 类型

  • 什么是 Element?它可以表示为 Widget 在树中特定位置的实例,一个 Element 可以形成一棵树(想想每个 Container 都有 Element,然后其 child 再套其它的 widget,这样就形成了一颗树)

  • Element 在此处将其理解为:本身 Widget 和其子节点形成的树,Element 是这棵树的头结点,这特定位置的节点是实例化的,对这个特定位置的实例节点操作,会影响到他的子节点

  • Widget 的 createElement()方法会实例化 Element

  • 这地方遍历_dependents 的 key 取 Element,可以猜测:他肯定是想取某个元素或者说某个 Widget

  • 取到相关 Element 实例后,她会传入 notifyDependent(oldWidget, dependent)方法中

  • 接下来,需要看看 notifyDependent(oldWidget, dependent)方法逻辑了


class InheritedElement extends ProxyElement {  final Map<Element, Object?> _dependents = HashMap<Element, Object?>();      ...      @override  void notifyClients(InheritedWidget oldWidget) {    assert(_debugCheckOwnerBuildTargetExists('notifyClients'));    for (final Element dependent in _dependents.keys) {      assert(() {        // check that it really is our descendant        Element? ancestor = dependent._parent;        while (ancestor != this && ancestor != null)          ancestor = ancestor._parent;        return ancestor == this;      }());      // check that it really depends on us      assert(dependent._dependencies!.contains(this));      notifyDependent(oldWidget, dependent);    }  }}
复制代码


  • notifyDependent

  • if (dependencies is _Dependency<T>) 这判断的逻辑题里面还有很多逻辑,是作者在 BuildContext 上面搞了一个 select 扩展方法(判断是否需要刷新),但和现在讲了刷新流程无关,我在里面绕了好久,凎!

  • 去掉上面的逻辑就简单了,shouldNotify 赋值为 true,最后调用 dependent.didChangeDependencies()

  • dependent 还记得是啥吗?是父类里面循环取得的 Element 实例

  • 这地方直接去掉 super 操作,这也是系统建议的,我们可以重写 notifyDependent 方法,自定义相关逻辑;因为有时我们需要可选择性的调用 dependent.didChangeDependencies()!


class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)      : super(widget);      ...
@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>) { ... } else { shouldNotify = true; } }
if (shouldNotify) { dependent.didChangeDependencies(); } }
...}
复制代码


  • didChangeDependencies

  • didChangeDependencies 逻辑就很简单了,会调用 markNeedsBuild()

  • 可以理解为:最终会调用该 Widget 的 build 方法

  • markNeedsBuild()就不讲了,内部涉及逻辑太多了,还涉及 bind 类,还会涉及到绘制流程,我嘞个去。。。


abstract class Element extends DiagnosticableTree implements BuildContext {  ...      @mustCallSuper  void didChangeDependencies() {    assert(_lifecycleState == _ElementLifecycle.active); // otherwise markNeedsBuild is a no-op    assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));    markNeedsBuild();  }
...}
复制代码


现在有个超纠结的事情,这个点关乎整个刷新流程的枢纽!

InheritedElement 中的_dependents 这个 map 的 key 是 Element,这个 Element 是什么?上面所有流程都是为了调用 _dependents 这个 Map 中 key(Element)的 markNeedsBuild()方法,最终是为了调用这个 Element 的 Widget 的 build 方法!

大家明白了吗?我们就算大胆去蒙,去猜,去赌,这个 Widget 十有八九就是 Consumer 这类刷新 Widget 啊!

但是!但是!他到底是怎么将这类刷新 Widget 添加到 InheritedElement 的 _dependents 变量中的呢 !?


  • 上述流程图示


BuildContext

插播一个小知识点,这个知识和下述内容相关,这边先介绍一下

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);}
复制代码


  • StatelessWidget:看下 StatelessWidget 对 BuildContext 的实现(StatefulWidget 同理,不贴了)

  • 代码超级简单,StatelessWidget 抽象了 build 方法,入参为 BuildContext

  • createElement()方法实例了 StatelessElement 类,并将 StatelessWidget 本身实例传入

  • StatelessElement 里面实现了 ComponentElement 的 build 方法:该方法调用了 widget 里面的 build 方法,并将本身的实例传入,流程通了,此处调用 StatelessWidget 的 build 方法,并传入了 BuildContext 的实现类

  • ComponentElement 的父类中肯定有实现 BuildContext,往上看看


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(); }}
复制代码


  • ComponentElement

  • ComponentElement 继承 Element,它抽象了一个 build 方法,StatelessElement 实现了这个方法,没毛病

  • 来看看 Element


abstract class ComponentElement extends Element {  ...    @protected  Widget build();
...}
复制代码


  • Element

  • Element 此处实现了 BuildContext,所以继承他的子类,直接将本身实例传给 BuildContext 就 OK 了

  • 如果没做什么骚操作,BuildContext 可以理解为:每个 Widget 都有对应的 Element( 通过 createElement()生成 ),Element 是 BuildContext 实现类


abstract class Element extends DiagnosticableTree implements BuildContext {   ...}
复制代码


  • Widget

  • Widget 抽象了一个 createElement()方法

  • 每个 Widget 的子类,理应都有自己对应的 Element


@immutableabstract class Widget extends DiagnosticableTree {  const Widget({ this.key });
final Key? key; @protected @factory Element createElement();
...}
复制代码


  • 图示



  • 关于 Widget 和 Element 再多说俩句


知道为什么好多文章说 Widget 对 Element 是一对多吗?

首先 Widget 是 Element 的一个配置描述,我们通过类似StatelessElement createElement() => StatelessElement(this),将 widget 本身的配置信息实例传入 XxxElemen(this)中,然后 XxxElement 可以通过传入的 Widget 配置信息去生成对应的 Element 实例

大家发现没?每一个 Widget 都有对应的 Element 实例!

假设写了下面这个 Widget

Widget _myWidget({Widget child}){
    return Container(width:30, height:30, child:child);
}

  • 咱们这样用

_myWidget(
    child: Container(
        child: _myWidget(),
    )
)

这不就对了嘛,只有一份 Widget 配置信息,但是会生成俩个 Element!

但是还是会有俩个 Widget 实例,但从配置信息层次上看,俩个 Widget 实例的配置信息都是一样的,所以是一份配置信息。。。

所以就有了 Widget 对 Element 是一对多的说法;反正我是这样理解的,仅供参考。。。

可能大佬们写文章,这些简单实例脑子自然生成,但是对这些没啥概念的靓仔,这或许就成了:一条定理或者既定概念

神奇的 Provider.of()

为了将上面的流程连接起来,需要一位神奇的魔术师登场,下面就要请上我们的王炸:Provider.of() !

将刷新组件添加到了 InheritedElement 中的_dependents 变量里,他到底是怎么做到的呢?


  • Provider.of() :下面就是该方法所有的逻辑,代码很少,实现的功能却很强!

  • of 方法中,会通过 _inheritedElementOf<T>(context)方法获取到,和当前 Widget 距离最近的(往父节点遍历)继承 InheritedElement 的 XxxElement

  • 上面是通过 _inheritedElementOf<T>(context)方法中的 context.getElementForInheritedWidgetOfExactType()方法去获取的;继承 InheritedElement 的 Widget 的子节点,是可以通过这个方法去拿到距离他最近的继承 InheritedElement 的 Widget 的 XxxElement 实例,同样的,也可以获取其中储存的数据

  • 你可能想,我拿到 继承 InheritedElement 的 XxxElement 的实例有啥?咱好好想想:我们拿到这个 XxxElement 实例后,我们不就可以往它的父类 InheritedElement 里面的 _dependents 的 map 变量塞值了吗?狂喜...

  • 它是怎么做到的呢?就是通过这个:context.dependOnInheritedElement(inheritedElement)


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!;}
复制代码


context.getElementForInheritedWidgetOfExactType()

这个 api 是怎么拿到父节点的 InheritedElement 的呢?


  • Element:因为 Element 是 BuildContext 实现类,所以直接来 Element 看逻辑就行了

  • getElementForInheritedWidgetOfExactType 返回是 _inheritedWidgets 变量

  • _inheritedWidgets 的 key:是需要找的继承 InheritedWidget 的 Widget

  • _updateInheritance:方法是将父节点 _inheritedWidgets 对象赋值给当前 Element 的 _inheritedWidgets 变量

  • 现只需要看下,有什么地方给_inheritedWidgets 这 Map 塞值就行了


abstract class Element extends DiagnosticableTree implements BuildContext {  ...        @mustCallSuper  void mount(Element? parent, dynamic newSlot) {    ...    _updateInheritance();  }      Map<Type, InheritedElement>? _inheritedWidgets;
...
@override InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() { assert(_debugCheckStateIsActiveForAncestorLookup()); final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T]; return ancestor; }
void _updateInheritance() { assert(_lifecycleState == _ElementLifecycle.active); _inheritedWidgets = _parent?._inheritedWidgets; }
...}
复制代码


  • InheritedElement

  • 齐活了: _inheritedWidgets![widget.runtimeType] = this

  • InheritedElement 中给自己父类 Element 的 _inheritedWidgets 变量塞值了(ProxyElement 最终继承还是 Element)

  • 父节点会将 _inheritedWidgets 变量,一级一级的赋值给子节点 Element 的 _inheritedWidgets 变量

  • 可以发现:寻找父节点的 InheritedElement,耗时极短,只需要从 Map 里面去拿值就行了


class InheritedElement extends ProxyElement {  ...
@override void _updateInheritance() { assert(_lifecycleState == _ElementLifecycle.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; }
...}
复制代码


dependOnInheritedElement


  • 关于 BuildContext 上面已经说过了,我们直接去 Element 类里面找 dependOnInheritedElement 方法,看看他的实现逻辑

  • 直接看最重要的代码 ancestor.updateDependencies(this, aspect):我们传入的继承了 InheritedElement 的 XxxElement,被传入了 updateDependencies 方法,然后他还将当前 Widget 的 Element 实例传入了 updateDependencies 方法中


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;  }
...}
复制代码


  • updateDependencies:流程终于完整的跑通了!

  • updateDependencies 方法调用了 setDependencies 方法

  • setDependencies 方法,将子 Widget 的 Element 实例赋值给了继承 InheritedElement 的类的 _dependents 变量


class InheritedElement extends ProxyElement {  ...        @protected  void setDependencies(Element dependent, Object? value) {    _dependents[dependent] = value;  }        @protected  void updateDependencies(Element dependent, Object? aspect) {    setDependencies(dependent, null);  }
...}
复制代码


  • 看下图示:这图调了好久,不规划下,线很容易交叉,吐血...


自定义 Builder

通过上面的分析,Provider 的 widget 定点刷新,已经不再神秘了...

学以致用,咱们来整一个自定义 Builder!


  • 自定义的 EasyBuilder 控件能起到和 Consumer 一样的刷新作用


class EasyBuilder<T> extends StatelessWidget {  const EasyBuilder(    this.builder, {    Key? key,  }) : super(key: key);
final Widget Function() builder;
@override Widget build(BuildContext context) { Provider.of<T>(context); return builder(); }}
复制代码


写下完整的使用


  • view


class CustomBuilderPage extends StatelessWidget {  final provider = CustomBuilderProvider();
@override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (BuildContext context) => provider, child: _buildPage(), ); }
Widget _buildPage() { return Scaffold( appBar: AppBar(title: Text('Provider-自定义Builder范例')), body: Center( child: EasyBuilder<CustomBuilderProvider>( () => Text( '点击了 ${provider.count} 次', style: TextStyle(fontSize: 30.0), ), ), ), floatingActionButton: FloatingActionButton( onPressed: () => provider.increment(), child: Icon(Icons.add), ), ); }}
///自定义Builderclass EasyBuilder<T> extends StatelessWidget { const EasyBuilder( 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(); }}
复制代码


  • 效果图


总结

以上,就将 Provider 的刷新机制完整的说完了~~


撒花 ✿✿ヽ(°▽°)ノ✿



如果那里写的欠妥,请各位大佬不吝赐教 ~ . ~

MultiProvider

在上面的刷新机制里面,我说了一个:ChangeNotifierProvider 这个类很重要,基本可以算是框架的主入口


  • 在这里,你可能有疑问了???

  • 这不对吧!

  • 我们一般不是在 main 主入口的写全局 Provider,要用到 MultiProvider,按理说:主入口应该是 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 代码(无限嵌套那个 Provider 就不讲了,很少用)

  • 源码 so easy,继承 Nested 类,Nested 可以优化一些布局嵌套问题,感兴趣的可查看:nested(pub)

  • 看源码,可以发现 MultiProvider 肯定不是主入口,这地方只是将 Provider 的套在顶层 Widget 上


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,        );}
复制代码


  • 上面的不是主入口,children 里面用了 ChangeNotifierProvider.value,来看看这个源码

  • ChangeNotifierProvider.value 是 ChangeNotifierProvider 的命名构造函数,实际上 ChangeNotifierProvider.value 是对 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,        );
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.value 是对 ChangeNotifierProvider 使用的一个优化呢?

  • 来看看下面这个俩种写法,实际上等同的


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: [ //简化版 ChangeNotifierProvider.value(value: ProSpanOneProvider()), //效果和上面等同 ChangeNotifierProvider(create: (context) => ProSpanOneProvider()), ]); }); }}
复制代码


  • 总结

  • 所以 ChangeNotifierProvider 类是非常重要的,基本是 Provider 的主入口,没毛病

  • 很多初始化的操作,都是借助从该类实例化的时候开始的

Consumer

Consumer 应该是我们日常,非常非常常用的一个控件了,他的源码很简单,结构也很清晰


作者还写很多:Consumer2、Consumer3、Consumer4、Consumer5、Consumer6;把我直接看懵了。。。



鄙人拙见,大可不必,这样会让 builder 参数变得十分迷惑;能用 Consumer2 到 Consumer6 了,直接用 Provider.of<T>(context),或许能让后来者更加清晰的读懂代码;而且使用 Consumer2 之类的,必须要在 Consumer 上面写相应的泛型,builder 方法里面写相应的参数,这和我直接写 Provider.of<T>(context)的工作量相差无几。。。


此处我们只需要看 Consumer 就行了,至于 Consumer2 到 Consumer6,就只是多封了几个 Provider.of<T>(context)。。。


  • Consumer

  • 结构很清晰,继承了 SingleChildStatelessWidget,重写了 buildWithChild 方法,在里面返回了 builder 函数

  • 请注意:这地方做了一个将 child 传到父类的操作;而且 buildWithChild 里面会传出一个 child 的,然后传到 builder 方法里


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, ); }}
复制代码


  • SingleChildStatelessWidget

  • 此处在抽象了一个 buildWithChild 方法,然后在 build 方法中调用了 buildWithChild 方法

  • 此处,将 context 和我们在外部传入的 child,都传给了 buildWithChild 方法

  • ok,Consumer 逻辑比较简单,大致就这么多了!


abstract class SingleChildStatelessWidget extends StatelessWidget implements SingleChildWidget {  const SingleChildStatelessWidget({Key? key, Widget? child})      : _child = child,        super(key: key);
final Widget? _child;
Widget buildWithChild(BuildContext context, Widget? child);
@override Widget build(BuildContext context) => buildWithChild(context, _child);
@override SingleChildStatelessElement createElement() { return SingleChildStatelessElement(this); }}
复制代码

Selector

Provider 还有很重要的刷新组建,条件刷新组件 Selector,来看看


  • 使用

  • 我这地方用了三层结构,将状态层解耦出去了

  • 对复杂模块能更好应对


class ProHighCounterPage extends StatelessWidget {  final provider = ProHighCounterProvider();
@override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (BuildContext context) => provider, child: _buildSelector(), ); }
Widget _buildSelector() { return Scaffold( appBar: AppBar(title: Text('Provider-Extended范例')), body: Center( child: Selector( shouldRebuild: (previous, next) { return true; }, selector: (context, provider) => provider, builder: (_, __, ___) { return Text('点击了 ${provider.state.count} 次', style: TextStyle(fontSize: 30.0)); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () => provider.increment(), child: Icon(Icons.add), ), ); }}
class ProHighCounterProvider extends ChangeNotifier { final state = ProExtendedCounterState();
void increment() { state.count++; notifyListeners(); }}
class ProExtendedCounterState { late int count;
ProExtendedCounterState() { count = 0; }}
复制代码


  • Selector

  • 看来 Selector0 才是重点,去看看 Selector0


class Selector<A, S> extends Selector0<S> {  Selector({    Key? key,    required ValueWidgetBuilder<S> builder,    required S Function(BuildContext, A) selector,    ShouldRebuild<S>? shouldRebuild,    Widget? child,  }) : super(          key: key,          shouldRebuild: shouldRebuild,          builder: builder,          selector: (context) => selector(context, Provider.of(context)),          child: child,        );}
复制代码


Selector0:主要逻辑在_Selector0State 中,下面三个判定为 true,都可以使 builder 方法执行刷新操作


  1. oldWidget != widget:如果 selector 的父节点刷新了,builder 也会刷新

  2. widget. _shouldRebuild != null && widget. _shouldRebuild!(value as T, selected):shouldRebuild 回调实现了,且返回为 true

  3. selector:selector 回调返回了 XxxProvider,XxxProvider 这个实例完全改变了(例:重新实例化赋值);且 shouldRebuild 回调未实现


class Selector0<T> extends SingleChildStatefulWidget {  Selector0({    Key? key,    required this.builder,    required this.selector,    ShouldRebuild<T>? shouldRebuild,    Widget? child,  })  : _shouldRebuild = shouldRebuild,        super(key: key, child: child);
final ValueWidgetBuilder<T> builder;
final T Function(BuildContext) selector;
final ShouldRebuild<T>? _shouldRebuild;
@override _Selector0State<T> createState() => _Selector0State<T>();}
class _Selector0State<T> extends SingleChildState<Selector0<T>> { T? value; Widget? cache; Widget? oldWidget;
@override Widget buildWithChild(BuildContext context, Widget? child) { final selected = widget.selector(context);
final shouldInvalidateCache = oldWidget != widget || (widget._shouldRebuild != null && widget._shouldRebuild!(value as T, selected)) || (widget._shouldRebuild == null && !const DeepCollectionEquality().equals(value, selected)); if (shouldInvalidateCache) { value = selected; oldWidget = widget; cache = widget.builder( context, selected, child, ); } return cache!; }
@override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty<T>('value', value)); }}
复制代码

手搓一个状态管理框架

看完 Provider 的原理后,大家是不是感觉胸中万千沟壑,腹中万千才华无法释放!咱们就来将自己想法统统释放出来吧!

学以致用,咱们就来按照 Provider 刷新机制,手搓一个状态管理框架。。。

手搓框架就叫:EasyP(后面应该还会接着写 Bloc 和 GetX;依次叫 EasyC,EasyX,省事...),取 Provider 的头字母

手搓状态框架

这个手搓框架做了很多简化,但是绝对保留了原汁原味的 Provider 刷新机制!


  • ChangeNotifierEasyP:类比 Provider 的 ChangeNotifierProvider

  • 代码做了大量的精简,只保留了 provider 的刷新机制的精髓

  • 代码我就不解释了,上面的刷新机制如果看懂了,下面的代码很容易理解;如果没看懂,我解释下面代码也没用啊。。。


class ChangeNotifierEasyP<T extends ChangeNotifier> extends InheritedWidget {  ChangeNotifierEasyP({    Key? key,    Widget? child,    required this.create,  }) : super(key: key, child: child ?? Container());
final T Function(BuildContext context) create;
@override bool updateShouldNotify(InheritedWidget oldWidget) => false;
@override InheritedElement createElement() => EasyPInheritedElement(this);}
class EasyPInheritedElement<T extends ChangeNotifier> extends InheritedElement { EasyPInheritedElement(ChangeNotifierEasyP<T> widget) : super(widget);
bool _firstBuild = true; bool _shouldNotify = false; late T _value; late void Function() _callBack;
T get value => _value;
@override void performRebuild() { if (_firstBuild) { _firstBuild = false; _value = (widget as ChangeNotifierEasyP<T>).create(this);
_value.addListener(_callBack = () { // 处理刷新逻辑,此处无法直接调用notifyClients // 会导致owner!._debugCurrentBuildTarget为null,触发断言条件,无法向后执行 _shouldNotify = true; markNeedsBuild(); }); }
super.performRebuild(); }
@override Widget build() { if (_shouldNotify) { _shouldNotify = false; notifyClients(widget); } return super.build(); }
@override void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) { //此处就直接刷新添加的监听子Element了,不各种super了 dependent.markNeedsBuild(); // super.notifyDependent(oldWidget, dependent); }
@override void unmount() { _value.removeListener(_callBack); _value.dispose(); super.unmount(); }}
复制代码


  • EasyP:类比 Provider 的 Provider 类


class EasyP {  /// 获取EasyP实例  /// 获取实例的时候,listener参数老是写错,这边直接用俩个方法区分了  static T of<T extends ChangeNotifier>(BuildContext context) {    return _getInheritedElement<T>(context).value;  }
/// 注册监听控件 static T register<T extends ChangeNotifier>(BuildContext context) { var element = _getInheritedElement<T>(context); context.dependOnInheritedElement(element); return element.value; }
/// 获取距离当前Element最近继承InheritedElement<T>的组件 static EasyPInheritedElement<T> _getInheritedElement<T extends ChangeNotifier>(BuildContext context) { var inheritedElement = context .getElementForInheritedWidgetOfExactType<ChangeNotifierEasyP<T>>() as EasyPInheritedElement<T>?;
if (inheritedElement == null) { throw EasyPNotFoundException(T); }
return inheritedElement; }}
class EasyPNotFoundException implements Exception { EasyPNotFoundException(this.valueType);
final Type valueType;
@override String toString() => 'Error: Could not find the EasyP<$valueType>';}
复制代码


  • build:最后整一个 Build 类就行了


class EasyPBuilder<T extends ChangeNotifier> extends StatelessWidget {  const EasyPBuilder(    this.builder, {    Key? key,  }) : super(key: key);
final Widget Function() builder;
@override Widget build(BuildContext context) { EasyP.register<T>(context); return builder(); }}
复制代码


大功告成,上面这三个类,就能起到和 Provider 一样的局部刷新功能!


刷新机制一模一样,绝对没有吹牛皮!


下面来看看怎么使用吧!

使用

用法基本和 Provider 一摸一样...


  • view


class CounterEasyPPage extends StatelessWidget {  final easyP = CounterEasyP();
@override Widget build(BuildContext context) { return ChangeNotifierEasyP( create: (BuildContext context) => easyP, child: _buildPage(), ); }
Widget _buildPage() { return Scaffold( appBar: AppBar(title: Text('自定义状态管理框架-EasyP范例')), body: Center( child: EasyPBuilder<CounterEasyP>(() { return Text( '点击了 ${easyP.count} 次', style: TextStyle(fontSize: 30.0), ); }), ), floatingActionButton: FloatingActionButton( onPressed: () => easyP.increment(), child: Icon(Icons.add), ), ); }}
复制代码


  • easyP


class CounterEasyP extends ChangeNotifier {  int count = 0;
void increment() { count++; notifyListeners(); }}
复制代码


  • 效果图:体验一下

  • 如果网页打不开,可能需要你清下浏览器缓存



全局 EasyP


  • 全局也是可以的,直接把 ChangeNotifierEasyP 类套在主入口,代码就不贴了,给大家看下效果图


总结

如果有靓仔的公司,不想使用第三方状态管理框架,完全可以参照 Provider 的刷新机制,撸一个状态管理框架出来!我上面已经撸了一个极简版,画龙画虎难画骨,上面我大致把他的骨架整好了;如果有需要的话,发挥你的聪明才智,copy 过去给他填充血肉吧。。。


如果大家看懂了 Provider 的刷新机制,就会发现 Provider 状态框架,对系统资源占用极低,它仅仅只使用了 ChangeNotifier,这仅仅是最基础的 Callback 回调,这会占用多少资源?刷新逻辑全是调用 Flutte 的 framework 层自带的那些 api(获取 InheritedElement 的内部操作很简单,有兴趣可以看看)。。。所以完全不用担心,他会占用多少资源,几乎忽略不计!

最后

一本秘籍

写完整篇文章,我突然感觉自己掌握一本武功秘籍!知道了怎么去写出高端大气上档次且深奥的项目!

我现在就来传授给大家...



  • 首先一定要善用面向接口编程的思想!

  • 如果要想非常深奥,深奥的自己都难以看懂,那直接滥用这种思想就稳了!

  • 多用各种设计模式,别和我扯什么简单易用,老夫写代码,就是设计模式一把梭,不管合适不合适,全怼上面

  • 一定要多用命令模式和访问者模式,就是要让自己的函数入参超高度可扩展,难以被别人和自己读懂

  • if else 内部逻辑直接抛弃,全用策略模式往上怼

  • 不管内部状态闭不闭环,状态模式直接强行闭环

  • for 要少用,多用 List 遍历,防止别人不懂你的良苦用心,一定在旁注释:迭代器模式

  • 外观模式,一般都是做一层外观吧,咱们直接搞俩层,三层外观类!代理模式五层代理类起步!

  • 对象或变量不管是不是只用一次,咱们全都缓存起来,将享元模式的思想贯彻到底

  • 变换莫测的就是桥接模式了,一般俩个维度桥接,咱们直接 9 个维度,俗话说的好,九九八十一难嘛,不是把你绕进去,就是把自己绕起来!头发和命,只有一个能活!

  • 所有的类与类绝不强耦合,一定要有中介类桥接,别人要喷你;你就自信的往后一仰,淡淡的说:“迪米特法则,了解一下。”

  • 最重要的,要多用 Framework 层的回调

  • 不管那个系统回调咱们懂不懂,都在里面整点代码,假装很懂

  • 最关键的时候,系统抽象类要继承,多写点自己的抽象方法,千万不能写注释,不然以后自己看懂了,咋办?


以上纯属调侃

切勿对号入座进 Provider,Provider 相关思想用的张弛有度,他所抽象的类,实际在多处实现了不同的实现类,大大的增加了扩展;而且他所继承的系统上下文类里,所抽象的方法,给了非常详尽的注释。

从 Provider 的源码上看,能看出 Provider 的作者绝对是个高手,必须对 framework 层有足够了解,才能写出那样精彩的刷新机制!

这是一个很优秀的框架!

我为啥写上面这些调侃?ε=(´ο`*)))唉,前人练手,后人抓头。。。

相关地址

  • 文章中 Demo 的 Github 地址:flutter_use

  • Web 效果:https://cnad666.github.io/flutter_use/web/index.html

  • 如果 provider 相关功能按钮没看到,可能需要你清下浏览器缓存

  • Windows:Windows平台安装包

  • 密码:xdd666


系列文章


发布于: 2021 年 06 月 30 日阅读数: 10
用户头像

小呆呆666

关注

2021,葬爱不在低调 2020.08.17 加入

还未添加个人简介

评论

发布
暂无评论
源码篇:Flutter Provider的另一面(万字图文+插件)