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


    前言

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

    我为啥要写这个插件呢?

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

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

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

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

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

    img

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

    使用

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

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

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

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

    插件

    • 插件github:provider_template
      • 使用中碰见什么bug,希望大家能及时给我提issue
    • 插件可以进入Android Studio的Setting里面,选择Plugins,然后搜索flutter provider,第一个,看图上红框标定的就是了,点击install安装即可

    image-20210521161541895

    • 来下看使用效果图

    provider

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

    image-20210521162324454

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

    image-20210605152137006

    • 快捷代码片段提示:我自己写了三个,如果老哥们还有其它的骚操作,需要各位提PR啊
      • 在这个文件里面添加就行了,大家可以参照写法:provider_template
      • 输入 provider 前缀便有提示

    image-20210605152343392

    写法

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

    • Provider.of(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) => _buildPage(context),
        );
      }
    
      Widget _buildPage(BuildContext context) {
        final provider = context.read<ProEasyCounterProvider>();
    
        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();
      }
    }
    

    获取注入的实例的方法有点长;所以我在 _buildPage(...) 这个方法中,将其提出来,单独赋值给了一个变量,方便后续使用

    插件生成代码

    插件生成代码分为俩个模式: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 {
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider(
          create: (BuildContext context) => CounterProvider(),
          builder: (context, child) => _buildPage(context),
        );
      }
    
      Widget _buildPage(BuildContext context) {
        final provider = context.read<CounterProvider>();
    
        return 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 {
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider(
          create: (BuildContext context) => CounterProvider(),
          builder: (context, child) => _buildPage(context),
        );
      }
    
      Widget _buildPage(BuildContext context) {
        final provider = context.read<CounterProvider>();
    
        return 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),
          ),
        );
      }
    }
    
    • 来看下效果图

    ChangeNotifier演示

    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方法,排除所有的测试类中使用的,然后断定我找对了,整个添加监听的链路是通顺的!

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

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

    img

    流转

    • 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的逻辑
    @immutable
    abstract class _Delegate<T> {
      _DelegateState<T, _Delegate<T>> createState();
    
      void debugFillProperties(DiagnosticPropertiesBuilder properties) {}
    }
    
    class _CreateInheritedProvider<T> extends _Delegate<T> {
      _CreateInheritedProvider({
        this.create,
        this.update,
        UpdateShouldNotify<T>? updateShouldNotify,
        this.debugCheckInvalidValueType,
        this.startListening,
        this.dispose,
      })  : assert(create != null || update != null),
            _updateShouldNotify = updateShouldNotify;
    
      final Create<T>? create;
      final T Function(BuildContext context, T? value)? update;
      final UpdateShouldNotify<T>? _updateShouldNotify;
      final void Function(T value)? debugCheckInvalidValueType;
      final StartListening<T>? startListening;
      final Dispose<T>? dispose;
    
      @override
      _CreateInheritedProviderState<T> createState() =>
          _CreateInheritedProviderState();
    }
    
    • 这里需要重新回顾下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();
      }
    
      ...
    }
    
    • 流程图示

    _delegate.createState()调用链

    _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();
      }
    
      ...
    }
    

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

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

    _DelegateState.element初始化链

    _CreateInheritedProviderState

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

    1. get 流程
      1. 我们传入的create会直接赋值给 _value,现在这个 _value,就是我们在外面传进来的那个XxxProvider实例了!
      2. 底下也调用了 startListening,说明从外面传进来的这个回调也调用了,将 上下文实例传进来的XxxProvider实例 作为入参传进了这个回调中,此处传进来的回调也通过 .call 被调用了!
    2. dispose 流程
      1. 调用startListening方法时,该方法会返回一个移除监听Function
      2. 移除监听的Function在dispose时被调用,移除给XxxProvider添加的监听
      3. 从外部传入的dispose方法,也在此处被执行
      4. 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在此处做了一个实现
      1. notifyClients()是一个非常非常重要的方法,它内部有个for循环,遍历了_dependents这个HashMap类型的所有key值, _dependents的key是Element类型
        1. 什么是Element?它可以表示为Widget在树中特定位置的实例,一个Element可以形成一棵树(想想每个Container都有Element,然后其child再套其它的widget,这样就形成了一颗树)
        2. Element在此处将其理解为:本身Widget和其子节点形成的树,Element是这棵树的头结点,这特定位置的节点是实例化的,对这个特定位置的实例节点操作,会影响到他的子节点
        3. Widget的createElement()方法会实例化Element
      2. 这地方遍历_dependents的key取Element,可以猜测:他肯定是想取某个元素或者说某个Widget
      3. 取到相关Element实例后,她会传入notifyDependent(oldWidget, dependent)方法中
      4. 接下来,需要看看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) 这判断的逻辑题里面还有很多逻辑,是作者在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
    @immutable
    abstract class Widget extends DiagnosticableTree {
      const Widget({ this.key });
    
      final Key? key;
        
      @protected
      @factory
      Element createElement();
    
      ...
    }
    
    • 图示

    BuildContext(StatelessWidget)

    • 关于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(30, height:30, child:child);
    }
    
    • 咱们这样用
    _myWidget(
        child: Container(
            child: _myWidget(),
        )
    )
    

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

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

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

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

    img

    神奇的Provider.of()

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

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

    • Provider.of() :下面就是该方法所有的逻辑,代码很少,实现的功能却很强!
      1. of方法中,会通过 _inheritedElementOf(context)方法获取到,和当前Widget距离最近的(往父节点遍历)继承InheritedElement的XxxElement
      2. 上面是通过 _inheritedElementOf(context)方法中的 context.getElementForInheritedWidgetOfExactType()方法去获取的;继承InheritedElement的Widget的子节点,是可以通过这个方法去拿到距离他最近的继承InheritedElement的Widget的XxxElement实例,同样的,也可以获取其中储存的数据
      3. 你可能想,我拿到 继承InheritedElement的XxxElement的实例有啥?咱好好想想:我们拿到这个XxxElement实例后,我们不就可以往它的父类InheritedElement里面的 _dependents的map变量塞值了吗?狂喜...
      4. 它是怎么做到的呢?就是通过这个: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);
      }
    
      ...
    }
    
    • 看下图示:这图调了好久,不规划下,线很容易交叉,吐血...

    Provider.of流程

    自定义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 {
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider(
          create: (BuildContext context) => CustomBuilderProvider(),
          builder: (context, child) => _buildPage(context),
        );
      }
    
      Widget _buildPage(BuildContext context) {
        final provider = context.read<CustomBuilderProvider>();
    
        return Scaffold(
          appBar: AppBar(title: Text('Provider-自定义Builder范例')),
          body: Center(
            child: EasyBuilder<CustomBuilderProvider>(
              () => Text(
                '点击了 ${provider.count} 次',
                style: TextStyle(fontSize: 30.0),
              ),
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () => provider.increment(),
            child: Icon(Icons.add),
          ),
        );
      }
    }
    
    ///自定义Builder
    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();
      }
    }
    
    • provider
    class CustomBuilderProvider extends ChangeNotifier {
      int count = 0;
    
      void increment() {
        count++;
        notifyListeners();
      }
    }
    
    • 效果图

    provider_custom_builder

    总结

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

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

    img

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

    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;把我直接看懵了。。。

    img

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

    此处我们只需要看Consumer就行了,至于Consumer2到Consumer6,就只是多封了几个Provider.of(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 StatelessWidget {
      ChangeNotifierEasyP({
        Key? key,
        required this.create,
        this.builder,
        this.child,
      }) : super(key: key);
    
      final T Function(BuildContext context) create;
    
      final Widget Function(BuildContext context)? builder;
      final Widget? child;
    
      @override
      Widget build(BuildContext context) {
        assert(
          builder != null || child != null,
          '$runtimeType  must specify a child',
        );
    
        return EasyPInherited(
          create: create,
          child: builder != null
              ? Builder(builder: (context) => builder!(context))
              : child!,
        );
      }
    }
    
    class EasyPInherited<T extends ChangeNotifier> extends InheritedWidget {
      EasyPInherited({
        Key? key,
        required Widget child,
        required this.create,
      }) : super(key: key, child: child);
    
      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(EasyPInherited<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 EasyPInherited<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<EasyPInherited<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 {
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierEasyP(
          create: (BuildContext context) => CounterEasyP(),
          builder: (context) => _buildPage(context),
        );
      }
    
      Widget _buildPage(BuildContext context) {
        final easyP = EasyP.of<CounterEasyP>(context);
    
        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();
      }
    }
    
    • 效果图:体验一下
      • 如果网页打不开,可能需要你清下浏览器缓存

    easy_p

    全局EasyP

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

    easy_p_global

    总结

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

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

    最后

    一本秘籍

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

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

    0B484D36

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

      • 如果要想非常深奥,深奥的自己都难以看懂,那直接滥用这种思想就稳了!
    • 多用各种设计模式,别和我扯什么简单易用,老夫写代码,就是设计模式一把梭,不管合适不合适,全怼上面

      • 一定要多用命令模式和访问者模式,就是要让自己的函数入参超高度可扩展,难以被别人和自己读懂
      • if else内部逻辑直接抛弃,全用策略模式往上怼
      • 不管内部状态闭不闭环,状态模式直接强行闭环
      • for要少用,多用List遍历,防止别人不懂你的良苦用心,一定在旁注释:迭代器模式
      • 外观模式,一般都是做一层外观吧,咱们直接搞俩层,三层外观类!代理模式五层代理类起步!
      • 对象或变量不管是不是只用一次,咱们全都缓存起来,将享元模式的思想贯彻到底
      • 变换莫测的就是桥接模式了,一般俩个维度桥接,咱们直接9个维度,俗话说的好,九九八十一难嘛,不是把你绕进去,就是把自己绕起来!头发和命,只有一个能活!
      • 所有的类与类绝不强耦合,一定要有中介类桥接,别人要喷你;你就自信的往后一仰,淡淡的说:“迪米特法则,了解一下。”
    • 最重要的,要多用Framework层的回调

      • 不管那个系统回调咱们懂不懂,都在里面整点代码,假装很懂
      • 最关键的时候,系统抽象类要继承,多写点自己的抽象方法,千万不能写注释,不然以后自己看懂了,咋办?

    以上纯属调侃

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

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

    这是一个很优秀的框架!

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

    相关地址

    系列文章

  • 相关阅读:
    Allow Zero Length 允许空字符串 ACCESS
    数据集永久字段的Visble 属性为何不起作用
    Microsoft Jet 数据库引擎 SQL 和 ANSI SQL 的比较
    Microsoft 数据访问组件 (MDAC) 的版本历史记录
    Windows 7 英文版操作系统中文软件乱码解决方法
    DBLookupComboBox 的初始值
    无法为更新定位行,一些值可能已在最后一次读取后已更改
    [hdu6428]Problem C. Calculate
    [hdu6437]Problem L. Videos
    [hdu6434]Problem I. Count
  • 原文地址:https://www.cnblogs.com/xdd666/p/14830845.html
Copyright © 2020-2023  润新知