当前位置 博文首页 > xdd666:源码篇:Flutter Provider的另一面(万字图文+插件)

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

    作者:xdd666 时间:2021-05-31 18:26

    前言

    阅读此文的彦祖,亦菲们,附送一枚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_plugin

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

    image-20210521162324454

    初始写法

    • 在写Provider的demo实例的时候,是按照下面这种写法的,毕竟下面这种写法,是非常正统且常见的一种写法
    class ProEasyCounterPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider(
          create: (BuildContext context) => ProEasyCounterProvider(),
          child: _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: () => 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,使用频率肯定很高,都这么写而且这么长,想想就头皮发麻,我方了呀。。。

    img

    优化写法

    上面那个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(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),
          ),
        );
      }
    }
    
    • 来看下效果图

    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!,
        );
      }
    }