前言

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

我为啥要写这个插件呢?

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

心愿这个插件,能加重应用Provider小伙们的一点工作量;插件外面的模板代码是通过我三思而行过的,如果各位靓仔有更好的模板代码,请在评论里贴出来,我感觉正当的话,会退出到插件里。

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

我会竭尽所能的将总体流程说分明,相干艰涩流程会联合图文,并给出相应小demo演示

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

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

应用

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

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

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

我切实不想分篇幅水赞啊,而且也是为了不便大家能够在一篇文章外面查阅相干常识(请联合掘金旁边的纲要食用),也不便我随时批改优化文章内容。。。

插件

  • 插件github:provider_template

    • 应用中碰见什么bug,心愿大家能及时给我提issue
  • 插件能够进入Android Studio的Setting外面,抉择Plugins,而后搜寻flutter provider,第一个,看图上红框标定的就是了,点击install装置即可

  • 来下看应用效果图

  • 如果你不喜爱这种命名形式,这里提供批改入口;也反对了长久化

    • 大家按需批改吧

初始写法

  • 在写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,应用频率必定很高,都这么写而且这么长,想想就头皮发麻,我方了呀。。。

优化写法

下面那个Provider.of写法,让我巨好受:走在回去的路上想,有什么办法能够优化呢?洗澡的时候想,有什么办法能够优化呢?

我转念一想,我这中央只是写个应用demo,我特么有必要这么纠结吗?!

然而,我就是纠结的一批啊,肯定有什么办法能够优化!(魔改框架? ...石乐志吧我)

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

既然ChangeNotifierProvider外面create参数,是承受了我实例化的ChangeNotifier对象,而后它外部存了起来,而后在Consume外面的builder办法外面分发给我,那我本人是不是也可把ChangeNotifier对象存起来!

  • 忽然间醍醐灌顶,思路就冲破了,而后就能够欢快的在这下面游玩了
class ProEasyCounterPage extends StatelessWidget {  final provider = ProEasyCounterProvider();  @override  Widget build(BuildContext context) {    return ChangeNotifierProvider(      create: (BuildContext context) => provider,      child: _buildPage(),    );  }  Widget _buildPage() {    return Scaffold(      appBar: AppBar(title: Text('Provider-Easy范例')),      body: Center(        child: Consumer<ProEasyCounterProvider>(          builder: (context, provider, child) {            return Text('点击了 ${provider.count} 次',                style: TextStyle(fontSize: 30.0));          },        ),      ),      floatingActionButton: FloatingActionButton(        onPressed: () => provider.increment(),        child: Icon(Icons.add),      ),    );  }}class ProEasyCounterProvider extends ChangeNotifier {  int count = 0;  void increment() {    count++;    notifyListeners();  }}

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

一个模块外面,会有很多中央用到provider,这样一改,霎时轻松很多,而且还不须要传context了。。。

在这下面咱们还能骚!还能简化!
  • 因为这里咱们间接应用咱们本人储存起来provider,所以能够进一步简化

    • Consumer进行了简化,builder办法外面参数,大部分状况不须要了
    • 我甚至都想把泛型去掉;看了下源码,应该很难去掉,泛型在框架外部起到了至关重要的作用
//原版Consumer<ProEasyCounterProvider>(builder: (context, provider, child) {    return Text(        '点击了 ${provider.count} 次',        style: TextStyle(fontSize: 30.0),    );   }),//简化Consumer<ProEasyCounterProvider>(builder: (_, __, ___) {    return Text(        '点击了 ${provider.count} 次',        style: TextStyle(fontSize: 30.0),    );}),    

浏览了Provider外部的源码后,发现:依照下面这样写是齐全没问题!会肯定水平上晋升效率!

凎!能够把插件和demo代码全改了!搞起!

插件生成代码

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

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

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

大家都是用Flutter的新手,对这种构造应该十分理解,state层是把数据层独立进去保护

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

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

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

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

  • view
import 'package:flutter/material.dart';import 'package:provider/provider.dart';import 'provider.dart';class CounterPage extends StatelessWidget {  final provider = CounterProvider();  @override  Widget build(BuildContext context) {    return ChangeNotifierProvider(      create: (BuildContext context) => provider,      child: Container(),    );  }}
  • provider
import 'package:flutter/material.dart';import 'state.dart';class CounterProvider extends ChangeNotifier {  final state = CounterState();}
  • state
class CounterState {  CounterState() {    // init some variables  }}

前置常识

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

Provider的刷新机制,相干流程相当之绕,我曾经全力以赴,精简了有数咱们不须要关注的代码,而后一步步带着你的思路去走一遍正确的流程,相干类还给了很多阐明,然而架不住源码流程山路十八弯,绕的一比啊!你如果不用心去看,去领会,会相当焦躁。。。

我曾经帮大家熬过最蛋筒的局部,相干绕的流程画了具体的图示,我曾经致力了;如果你想晓得Provider外部运行机制,当初就须要你致力了!

ChangeNotifier的独自应用

ValueListenableBuilder和ValueNotifier能够配套应用,ValueListenableBuilder外部也是一个StatefulWidget,代码很简略,感兴趣的能够本人查看

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

大家必定在Provider都写过继承ChangeNotifier的代码,而且写的十分多,然而大家晓得怎么独自应用ChangeNotifier,以达到管制界面变动的成果吗?

我搜了很多怎么独自应用ChangeNotifier的文章,然而根本都是写配合ChangeNotifierProvider在Provider中应用的,我佛了呀,搜到寥寥无几的文章,也没说分明,怎么独自应用;我想这玩意是不是有个独自XxxWidgetBuild配合应用?然而!我怎么都找不到,气抖冷!

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

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

  • TextEditingController理论是继承了ValueNotifier,来看下ValueNotifier
class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {  ValueNotifier(this._value);  @override  T get value => _value;  T _value;  set value(T newValue) {    if (_value == newValue)      return;    _value = newValue;    notifyListeners();  }  @override  String toString() => '${describeIdentity(this)}($value)';}

ValueNotifier理论是对ChangeNotifier的封装

这里影响不大,咱们还是应用ChangeNotifier,来写一个相似TextField中的控制器成果,每当控制器中的数值扭转,其控件内容就自动更新

  • 先应用ChangeNotifier搞一个控制器
class TestNotifierController extends ChangeNotifier {  String _value = '0';  String get value => _value;  set value(String newValue) {    if (_value == newValue) return;    _value = newValue;    notifyListeners();  }}
  • 搭配这个控制器的Widget

    • OK,这样就搞定了,扭转控制器的数据,Widget也会主动刷新
    • 我把性能颗粒度压缩的十分小,心愿大家浏览会比拟轻松
class TestNotifierWidget extends StatefulWidget {  const TestNotifierWidget({    Key? key,    this.controller,  }) : super(key: key);  final TestNotifierController? controller;  @override  _TestNotifierState createState() => _TestNotifierState();}class _TestNotifierState extends State<TestNotifierWidget> {  @override  void initState() {    ///增加回调 value扭转时,主动触发回调内容    widget.controller?.addListener(_change);    super.initState();  }  @override  Widget build(BuildContext context) {    return Text(      widget.controller?.value ?? '初始值为空',      style: TextStyle(fontSize: 30.0),    );  }  ///被触发的回调  void _change() {    setState(() {});  }}
  • 来看下怎么应用这个控件

    • 应用代码曾经非常简单了:onPressed扭转了控制器数值内容,TestNotifierWidget控件会主动刷新
class TestNotifierPage extends StatelessWidget {  @override  Widget build(BuildContext context) {    final controller = TestNotifierController();    var count = 0;    return Scaffold(      appBar: AppBar(title: Text('ChangeNotifier应用演示')),      body: Center(        child: TestNotifierWidget(controller: controller),      ),      floatingActionButton: FloatingActionButton(        onPressed: () {          controller.value = '数值变动:${(++count).toString()}';        },        child: Icon(Icons.add),      ),    );  }}
  • 来看下效果图

Function Call()

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

每个Function都有个Call()办法

  • 上面俩种形式调用是等同的,都能调用test办法
void main(){    test();    test.call();}void test(){    print('test');}

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

来看下一个小范例,就晓得这个货色能帮咱们简化很多代码

  • 平时封装带有CallBack回调Widget

    • 这边写了俩个自定义的点击回调判断操作
    • 如果不做判空操作,内部未实现这个Function,点击事件会报空异样
class TestWidget extends StatelessWidget {  const TestWidget({    Key? key,    this.onTap,    this.onBack,  }) : super(key: key);  final VoidCallback? onTap;      final VoidCallback? onBack;  @override  Widget build(BuildContext context) {    return GestureDetector(      onTap: () {        if (onTap != null) {          onTap!();        }        if (onBack != null) {          onBack!();        }      },      child: Container(),    );  }}
  • 应用 .call() 后,能够怎么写呢?

    • 能够干掉麻烦的if判空操作了!
class TestWidget extends StatelessWidget {  const TestWidget({    Key? key,    this.onTap,    this.onBack,  }) : super(key: key);  final VoidCallback? onTap;      final VoidCallback? onBack;  @override  Widget build(BuildContext context) {    return GestureDetector(      onTap: () {        onTap?.call();        onBack?.call();      },      child: Container(),    );  }}

刷新机制

Provider的刷新机制是十分重要的,只有把Provider的刷新机制搞清楚,这个框架在你背后,将不在神秘!

实际上,大家只有看到ChangeNotifier的利用,那必定晓得,这就是个观察者模式,然而问题是:它的监听在何处增加?增加的监听逻辑是否有残缺的初始化链路?监听逻辑是什么?为什么触发监听逻辑,能导致相应控件刷新?

  • 下面初始化的残缺链路看的真是有点蛋痛

    • 源码东一榔锤西一棒的,而且还用了大量了抽象类,想间接定位逻辑,那是不可能的,你必须找到实现类赋值的中央,能力明确外部运行
    • 不搞清楚残缺初始化链路,心田就相当于膈应,明晓得他必定初始化了,却不晓得他在哪初始化的,就很好受
    • 我上面将相干流程理了一遍,心愿对大家有所帮忙
  • 要读懂Provider,必须要有个前提,明确什么观察者模式:观察者模式其实很简略,简略形容下

    • 定义个List类型,泛型为一个抽象类,初始化这个List
    • 而后给这个List,add这个抽象类的实现类实例
    • 某个适合时候,遍历这个List所有实例,触发所有实例的某个办法
    • 如果将这个思维和反射注解联合在一起,就能大大拓宽它的应用面,例如android里的EventBus。。。

总流程

继承ChangeNotifier的类,是通过ChangeNotifierProvider传入到Provider外部,很显著ChangeNotifierProvider这个类很重要,根本能够算是框架的主入口

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

  • ChangeNotifierProvider

    • 这中央有个_dispose回调,是定义好的,外部逻辑是回收ChangeNotifier实例
    • 这里将该办法赋值给了他的父类ListenableProvider,而后一层层往上回溯
class ChangeNotifierProvider<T extends ChangeNotifier?> extends ListenableProvider<T> {  ChangeNotifierProvider({    Key? key,    required Create<T> create,    bool? lazy,    TransitionBuilder? builder,    Widget? child,  }) : super(          key: key,          create: create,          dispose: _dispose,          lazy: lazy,          builder: builder,          child: child,        );      ...        static void _dispose(BuildContext context, ChangeNotifier? notifier) {    notifier?.dispose();  }}
  • ListenableProvider

    • 这中央有个_startListening回调,这个办法极其重要
class ListenableProvider<T extends Listenable?> extends InheritedProvider<T> {  ListenableProvider({    Key? key,    required Create<T> create,    Dispose<T>? dispose,    bool? lazy,    TransitionBuilder? builder,    Widget? child,  }) : super(          key: key,          startListening: _startListening,          create: create,          dispose: dispose,          lazy: lazy,          builder: builder,          child: child,        );        ...        static VoidCallback _startListening(InheritedContext e, Listenable? value,) {    value?.addListener(e.markNeedsNotifyDependents);    return () => value?.removeListener(e.markNeedsNotifyDependents);  }}
  • InheritedProvider

    • 这个类就是逻辑的纠缠点了:我省略了大量和主流程无关的代码,不然会非常影响你的关注点,会很好受
    • 这里就不须要看他的父类了,他的父类是SingleChildStatelessWidget,这个类是对StatelessWidget类的一个封装,能略微优化下嵌套问题,无关紧要
    • 须要看下buildWithChild(看成StatelessWidget的build办法就行了)办法外面的_InheritedProviderScope类,来看下他的源码
class InheritedProvider<T> extends SingleChildStatelessWidget {  InheritedProvider({    Key? key,    Create<T>? create,    T Function(BuildContext context, T? value)? update,    UpdateShouldNotify<T>? updateShouldNotify,    void Function(T value)? debugCheckInvalidValueType,    StartListening<T>? startListening,    Dispose<T>? dispose,    this.builder,    bool? lazy,    Widget? child,  })  : _lazy = lazy,        _delegate = _CreateInheritedProvider(          create: create,          update: update,          updateShouldNotify: updateShouldNotify,          debugCheckInvalidValueType: debugCheckInvalidValueType,          startListening: startListening,          dispose: dispose,        ),        super(key: key, child: child);      ...        final _Delegate<T> _delegate;  final bool? _lazy;  final TransitionBuilder? builder;  ...  @override  Widget buildWithChild(BuildContext context, Widget? child) {    ...    return _InheritedProviderScope<T>(      owner: this,      debugType: kDebugMode ? '$runtimeType' : '',      child: builder != null          ? Builder(              builder: (context) => builder!(context, child),            )          : child!,    );  }}
  • _InheritedProviderScope

    • 这里是继承了InheritedWidget,外面重写createElement办法,在构建Widget的时候,这个办法是必定会被调用的!
    • 马上就要到最重要的类了,就是createElement中实例化的_InheritedProviderScopeElement类!
class _InheritedProviderScope<T> extends InheritedWidget {  const _InheritedProviderScope({    required this.owner,    required this.debugType,    required Widget child,  }) : super(child: child);  final InheritedProvider<T> owner;  final String debugType;  @override  bool updateShouldNotify(InheritedWidget oldWidget) {    return false;  }  @override  _InheritedProviderScopeElement<T> createElement() {    return _InheritedProviderScopeElement<T>(this);  }}
  • _InheritedProviderScopeElement:实现办法外面的逻辑全省略了,逻辑太多,看着头晕

    • 先阐明下,这个类是极其极其重要的!大家能够看下他实现了一个什么抽象类:InheritedContext!
    • InheritedContext继承了BuildContext,也就是说,这里作者实现了BuildContext所有形象办法

      • 是的,BuildContext也是个抽象类,咱们能够去实现多个不同实现类
      • 外部零碎只须要特定的周期去触发相应办法,就能够了
      • 你能够在相应的办法外面实现本人的逻辑,大大的扩大了逻辑,怎么说呢?有点策略模式滋味,能够动静替换实现类
    • _InheritedProviderScopeElement算是实现了:InheritedContext和BuildContext;BuildContext中有很多办法是和控件生命周期挂钩的,例如热重载触发(reassemble),setState触发(build、performRebuild)、以及很有意思的强制依赖项组件刷新(markNeedsNotifyDependents:这是Provider作者在InheritedContext中形象的办法)。。。
abstract class InheritedContext<T> extends BuildContext {  T get value;  void markNeedsNotifyDependents();  bool get hasValue;}class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)      : super(widget);  ...  @override  void mount(Element? parent, dynamic newSlot) {    ...  }  @override  _InheritedProviderScope<T> get widget => super.widget as _InheritedProviderScope<T>;  @override  void reassemble() {    ...  }  @override  void updateDependencies(Element dependent, Object? aspect) {    ...  }  @override  void notifyDependent(InheritedWidget oldWidget, Element dependent) {    ...  }  @override  void performRebuild() {    ...  }  @override  void update(_InheritedProviderScope<T> newWidget) {    ...  }  @override  void updated(InheritedWidget oldWidget) {    ...  }  @override  void didChangeDependencies() {    ...  }  @override  Widget build() {    ...  }  @override  void unmount() {    ...  }  @override  bool get hasValue => _delegateState.hasValue;  @override  void markNeedsNotifyDependents() {    ...  }  bool _debugSetInheritedLock(bool value) {    ...  }  @override  T get value => _delegateState.value;  @override  InheritedWidget dependOnInheritedElement(    InheritedElement ancestor, {    Object? aspect,  }) {    ...  }  @override  void debugFillProperties(DiagnosticPropertiesBuilder properties) {    ...  }}

下面进行了五步的回溯流程,如果不认真看清楚相干类外面的逻辑,很可能就迷失在super办法里。。。

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

  • 图示

    • 下面回溯的层级过多,还有很多的继承和实现
    • 看了后,脑中可能没啥印象,所以此处画了流程图,能够参照比照

增加监听

整个刷新机制外面有个相当重要的一环,咱们从Create中传入的类,它外部是怎么解决的?

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

就算没看源码,我也能判定传入的XxxProvider实例,必定应用了其自身的addListener办法!

然而找这个addListener办法,切实让我找自闭了,之前因为没梳理总流程,对其初始化链路不清晰,找到了addListener办法,我都非常狐疑,是不是找对了、其它中央是不是还有addListener办法;起初没方法,就把Provider源码下载下来(之前间接我的项目外面点Provider插件源码看的),全局搜寻addListener办法,排除所有的测试类中应用的,而后判定我找对了,整个增加监听的链路是通顺的!

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

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

流转

  • ChangeNotifierProvider

    • 明确下Create是一个Function,返回继承ChangeNotifier类的实例
    • 这里肯定要记住create这个变量的走向,其中的T就是继承ChangeNotifier类的要害类
    • 减少了_dispose办法,传给了父类
    • create这里super给其父类,回溯下父类
typedef Create<T> = T Function(BuildContext context);class ChangeNotifierProvider<T extends ChangeNotifier?> extends ListenableProvider<T> {  ChangeNotifierProvider({    Key? key,    required Create<T> create,    bool? lazy,    TransitionBuilder? builder,    Widget? child,  }) : super(          key: key,          create: create,          dispose: _dispose,          lazy: lazy,          builder: builder,          child: child,        );      ...        static void _dispose(BuildContext context, ChangeNotifier? notifier) {    notifier?.dispose();  }}
  • ListenableProvider

    • 此处将create实例super给了父类
    • 还减少一个_startListening办法,也同样给了父类
class ListenableProvider<T extends Listenable?> extends InheritedProvider<T> {  ListenableProvider({    Key? key,    required Create<T> create,    Dispose<T>? dispose,    bool? lazy,    TransitionBuilder? builder,    Widget? child,  }) : super(          key: key,          startListening: _startListening,          create: create,          dispose: dispose,          lazy: lazy,          builder: builder,          child: child,        );  ...   static VoidCallback _startListening(InheritedContext e, Listenable? value,) {    value?.addListener(e.markNeedsNotifyDependents);    return () => value?.removeListener(e.markNeedsNotifyDependents);  }}
  • InheritedProvider

    • 这中央和下面总流程不太一样了
    • create、dispose、startListening传给了_CreateInheritedProvider
    • 须要看下_CreateInheritedProvider
class InheritedProvider<T> extends SingleChildStatelessWidget {  InheritedProvider({    Key? key,    Create<T>? create,    T Function(BuildContext context, T? value)? update,    UpdateShouldNotify<T>? updateShouldNotify,    void Function(T value)? debugCheckInvalidValueType,    StartListening<T>? startListening,    Dispose<T>? dispose,    this.builder,    bool? lazy,    Widget? child,  })  : _lazy = lazy,        _delegate = _CreateInheritedProvider(          create: create,          update: update,          updateShouldNotify: updateShouldNotify,          debugCheckInvalidValueType: debugCheckInvalidValueType,          startListening: startListening,          dispose: dispose,        ),        super(key: key, child: child);  ...}
  • 流程图示

_CreateInheritedProvider

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

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

  • _CreateInheritedProvider阐明

    • _CreateInheritedProvider继承了抽象类 _Delegate,实现了其createState形象办法
    • 按理说,次要逻辑必定在createState办法中_CreateInheritedProviderState实例中
    • 必须要看下_CreateInheritedProvider实例,在何处调用 createState办法,而后能力持续看 _CreateInheritedProviderState的逻辑
@immutableabstract class _Delegate<T> {  _DelegateState<T, _Delegate<T>> createState();  void debugFillProperties(DiagnosticPropertiesBuilder properties) {}}class _CreateInheritedProvider<T> extends _Delegate<T> {  _CreateInheritedProvider({    this.create,    this.update,    UpdateShouldNotify<T>? updateShouldNotify,    this.debugCheckInvalidValueType,    this.startListening,    this.dispose,  })  : assert(create != null || update != null),        _updateShouldNotify = updateShouldNotify;  final Create<T>? create;  final T Function(BuildContext context, T? value)? update;  final UpdateShouldNotify<T>? _updateShouldNotify;  final void Function(T value)? debugCheckInvalidValueType;  final StartListening<T>? startListening;  final Dispose<T>? dispose;  @override  _CreateInheritedProviderState<T> createState() =>      _CreateInheritedProviderState();}
  • 这里须要从新回顾下InheritedProvider类

    • 这中央做了一个很重要的操作,将_CreateInheritedProvider实例赋值给 _delegate
    • buildWithChild办法中_InheritedProviderScope的owner承受了InheritedProvider自身的实例
    • 联合这俩个就有戏了,再来看下_InheritedProviderScope类
class InheritedProvider<T> extends SingleChildStatelessWidget {  InheritedProvider({    Key? key,    Create<T>? create,    T Function(BuildContext context, T? value)? update,    UpdateShouldNotify<T>? updateShouldNotify,    void Function(T value)? debugCheckInvalidValueType,    StartListening<T>? startListening,    Dispose<T>? dispose,    this.builder,    bool? lazy,    Widget? child,  })  : _lazy = lazy,        _delegate = _CreateInheritedProvider(          create: create,          update: update,          updateShouldNotify: updateShouldNotify,          debugCheckInvalidValueType: debugCheckInvalidValueType,          startListening: startListening,          dispose: dispose,        ),        super(key: key, child: child);      final _Delegate<T> _delegate;  final bool? _lazy;      ...  @override  Widget buildWithChild(BuildContext context, Widget? child) {    ,,,    return _InheritedProviderScope<T>(      owner: this,      debugType: kDebugMode ? '$runtimeType' : '',      child: builder != null          ? Builder(              builder: (context) => builder!(context, child),            )          : child!,    );  }}
  • _InheritedProviderScope

    • createElement办法传入_InheritedProviderScope自身的实例
    • 要害的在_InheritedProviderScopeElement类中
class _InheritedProviderScope<T> extends InheritedWidget {  const _InheritedProviderScope({    required this.owner,    required this.debugType,    required Widget child,  }) : super(child: child);  final InheritedProvider<T> owner;  final String debugType;  @override  bool updateShouldNotify(InheritedWidget oldWidget) {    return false;  }  @override  _InheritedProviderScopeElement<T> createElement() {    return _InheritedProviderScopeElement<T>(this);  }}
  • _InheritedProviderScopeElement类,我就间接精简到要害代码了

    • 有没有感觉InheritedWidget很像StatefulWidget,理论他俩最终都是继承Widget,未对Widget的建造者模式那层封装,所以有俩层构造;而StatelessWidget将建造者模式那层进行了封装,所以只有一层构造
    • 上面的要害代码看到没!widget.owner._delegate.createState() ... 这中央调用了_CreateInheritedProvider类的createState() 办法,安心了
    • performRebuild:该回调会在setState或者build的时候会触发;此处做了一个判断,只会在第一次build的时候触发
    • 这里能够确定_CreateInheritedProvider类中的createState办法肯定会被调用;接下来看看其办法外面调用的 _CreateInheritedProviderState类
class _InheritedProviderScopeElement<T> extends InheritedElement    implements InheritedContext<T> {  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)      : super(widget);  ...  @override  void performRebuild() {    if (_firstBuild) {      _firstBuild = false;      _delegateState = widget.owner._delegate.createState()..element = this;    }    super.performRebuild();  }  ...}
  • 流程图示

_InheritedProviderScopeElement

  • _CreateInheritedProviderState:这个类做了很多事件,很多的主体逻辑的都在此解决

    • 该类代码很多,此处只留下咱们须要关注的代码,因为省略了很多代码,从上面的主体代码来看,流程就分明了:create、startListening、dispose 都有
    • 然而这些变量是附丽在delegate上的,这个delegate是个啥?须要看下继承的抽象类 _DelegateState
class _CreateInheritedProviderState<T> extends _DelegateState<T, _CreateInheritedProvider<T>> {  VoidCallback? _removeListener;  bool _didInitValue = false;  T? _value;  _CreateInheritedProvider<T>? _previousWidget;  @override  T get value {    ...    if (!_didInitValue) {      _didInitValue = true;      if (delegate.create != null) {        assert(debugSetInheritedLock(true));        try {          ...          _value = delegate.create!(element!);        } finally {          ...        }        ...      }      ...    }    element!._isNotifyDependentsEnabled = false;    _removeListener ??= delegate.startListening?.call(element!, _value as T);    element!._isNotifyDependentsEnabled = true;    assert(delegate.startListening == null || _removeListener != null);    return _value as T;  }  @override  void dispose() {    super.dispose();    _removeListener?.call();    if (_didInitValue) {      delegate.dispose?.call(element!, _value as T);    }  }  ...}
  • _DelegateState

    • delegate是通过 _InheritedProviderScopeElement的实例获取到了owner而后获取到了 _delegate变量
    • _delegate这个变量是在InheritedProvider类中的实例化 _CreateInheritedProvider赋值给他的,不信的话,能够返回去看看
    • 好吉尔绕!!!
abstract class _DelegateState<T, D extends _Delegate<T>> {  _InheritedProviderScopeElement<T>? element;  T get value;  D get delegate => element!.widget.owner._delegate as D;  bool get hasValue;  bool debugSetInheritedLock(bool value) {    return element!._debugSetInheritedLock(value);  }  bool willUpdateDelegate(D newDelegate) => false;  void dispose() {}  void debugFillProperties(DiagnosticPropertiesBuilder properties) {}  void build({required bool isBuildFromExternalSources}) {}}
  • element

    • 当初还有个问题,element这个变量在哪实例化的?怎么大家这么轻易用它!就不怕它为空吗?
    • 间接带大家来_InheritedProviderScopeElement外面看了,下面曾经回顾了到这个必然实例化这个上下文类的流程
    • performRebuild回调中,在调用createState()办法的时候,给element赋值了,element = this
    • 所以在_CreateInheritedProviderState类中,能够轻易应用element 这个变量,他的值必定不为空!
class _InheritedProviderScopeElement<T> extends InheritedElement    implements InheritedContext<T> {  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)      : super(widget);  ...  @override  void performRebuild() {    if (_firstBuild) {      _firstBuild = false;      _delegateState = widget.owner._delegate.createState()..element = this;    }    super.performRebuild();  }  ...}

不晓得大家对这流程有没有个清晰的印象

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

_CreateInheritedProviderState

有了下面剖析出的element和_delegate不为空的,且 _delegate能间接拜访 _CreateInheritedProvider这个实例根底,再来看下 _CreateInheritedProviderState代码

  1. get 流程

    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<T>) 这判断的逻辑题外面还有很多逻辑,是作者在BuildContext下面搞了一个select扩大办法(判断是否须要刷新),但和当初讲了刷新流程无关,我在外面绕了良久,凎!
    • 去掉下面的逻辑就简略了,shouldNotify赋值为true,最初调用dependent.didChangeDependencies()
    • dependent还记得是啥吗?是父类外面循环获得的Element实例
    • 这中央间接去掉super操作,这也是零碎倡议的,咱们能够重写notifyDependent办法,自定义相干逻辑;因为有时咱们须要可选择性的调用dependent.didChangeDependencies()!
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {  _InheritedProviderScopeElement(_InheritedProviderScope<T> widget)      : super(widget);      ...  @override  void notifyDependent(InheritedWidget oldWidget, Element dependent) {    final dependencies = getDependencies(dependent);    if (kDebugMode) {      ProviderBinding.debugInstance.providerDidChange(_debugId);    }    var shouldNotify = false;    if (dependencies != null) {      if (dependencies is _Dependency<T>) {        ...      } else {        shouldNotify = true;      }    }    if (shouldNotify) {      dependent.didChangeDependencies();    }  }  ...}
  • didChangeDependencies

    • didChangeDependencies逻辑就很简略了,会调用markNeedsBuild()
    • 能够了解为:最终会调用该Widget的build办法
    • markNeedsBuild()就不讲了,外部波及逻辑太多了,还波及bind类,还会波及到绘制流程,我嘞个去。。。
abstract class Element extends DiagnosticableTree implements BuildContext {  ...      @mustCallSuper  void didChangeDependencies() {    assert(_lifecycleState == _ElementLifecycle.active); // otherwise markNeedsBuild is a no-op    assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));    markNeedsBuild();  }  ...}

当初有个超纠结的事件,这个点关乎整个刷新流程的枢纽!

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

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

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

  • 上述流程图示

BuildContext

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

BuildContext是什么?

  • BuildContext

    • 每个形象办法下面正文超级多,我删掉了(占篇幅),有趣味的能够本人去源码里看看
    • BuildContext就是抽象类,是约定好的一个抽象类,相干办法的性能曾经被约定,你如果想实现这个抽象类类,相干办法性能实现能够有出入,但不应该偏离形象办法正文所形容的性能范畴
abstract class BuildContext {  Widget get widget;  BuildOwner? get owner;  bool get debugDoingBuild;  RenderObject? findRenderObject();  Size? get size;  InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect });  T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object? aspect });  InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>();  T? findAncestorWidgetOfExactType<T extends Widget>();  T? findAncestorStateOfType<T extends State>();  T? findRootAncestorStateOfType<T extends State>();  T? findAncestorRenderObjectOfType<T extends RenderObject>();  void visitAncestorElements(bool Function(Element element) visitor);  void visitChildElements(ElementVisitor visitor);  DiagnosticsNode describeElement(String name, {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty});  DiagnosticsNode describeWidget(String name, {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty});  List<DiagnosticsNode> describeMissingAncestor({ required Type expectedAncestorType });  DiagnosticsNode describeOwnershipChain(String name);}
  • StatelessWidget:看下StatelessWidget对BuildContext的实现(StatefulWidget同理,不贴了)

    • 代码超级简略,StatelessWidget形象了build办法,入参为BuildContext
    • createElement()办法实例了StatelessElement类,并将StatelessWidget自身实例传入
    • StatelessElement外面实现了ComponentElement的build办法:该办法调用了widget外面的build办法,并将自身的实例传入,流程通了,此处调用StatelessWidget的build办法,并传入了BuildContext的实现类
    • ComponentElement的父类中必定有实现BuildContext,往上看看
abstract class StatelessWidget extends Widget {  const StatelessWidget({ Key? key }) : super(key: key);  @override  StatelessElement createElement() => StatelessElement(this);  @protected  Widget build(BuildContext context);}class StatelessElement extends ComponentElement {  StatelessElement(StatelessWidget widget) : super(widget);  @override  StatelessWidget get widget => super.widget as StatelessWidget;  @override  Widget build() => widget.build(this);  @override  void update(StatelessWidget newWidget) {    super.update(newWidget);    assert(widget == newWidget);    _dirty = true;    rebuild();  }}
  • ComponentElement

    • ComponentElement继承Element,它形象了一个build办法,StatelessElement实现了这个办法,没故障
    • 来看看Element
abstract class ComponentElement extends Element {  ...    @protected  Widget build();  ...}
  • Element

    • Element此处实现了BuildContext,所以继承他的子类,间接将自身实例传给BuildContext就OK了
    • 如果没做什么骚操作,BuildContext能够了解为:每个Widget都有对应的Element( 通过createElement()生成 ),Element是BuildContext实现类
abstract class Element extends DiagnosticableTree implements BuildContext {     ...}
  • Widget

    • Widget形象了一个createElement()办法
    • 每个Widget的子类,理当都有本人对应的Element
@immutableabstract class Widget extends DiagnosticableTree {  const Widget({ this.key });  final Key? key;      @protected  @factory  Element createElement();  ...}
  • 图示

  • 对于Widget和Element再多说俩句

晓得为什么好多文章说Widget对Element是一对多吗?

首先Widget是Element的一个配置形容,咱们通过相似StatelessElement createElement() => StatelessElement(this),将widget自身的配置信息实例传入XxxElemen(this)中,而后XxxElement能够通过传入的Widget配置信息去生成对应的Element实例

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

假如写了上面这个Widget

Widget _myWidget({Widget child}){    return Container(width:30, height:30, child:child);}
  • 咱们这样用
_myWidget(    child: Container(        child: _myWidget(),    ))

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

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

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

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

神奇的Provider.of()

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

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

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

    1. of办法中,会通过 _inheritedElementOf<T>(context)办法获取到,和以后Widget间隔最近的(往父节点遍历)继承InheritedElement的XxxElement
    2. 下面是通过 _inheritedElementOf<T>(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!;}
  • dependOnInheritedElement

    • BuildContext中的dependOnInheritedElement办法点进去是个形象办法,毕竟BuildContext是个纯抽象类,办法都没有逻辑
    • 对于BuildContext下面曾经说过了,咱们间接去Element类外面找dependOnInheritedElement办法,看看他的实现逻辑
    • 间接看最重要的代码 ancestor.updateDependencies(this, aspect):咱们传入的继承了InheritedElement的XxxElement,被传入了updateDependencies办法,而后他还将以后Widget的Element实例传入了updateDependencies办法中
abstract class Element extends DiagnosticableTree implements BuildContext {  ...      @override  InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {    assert(ancestor != null);    _dependencies ??= HashSet<InheritedElement>();    _dependencies!.add(ancestor);    ancestor.updateDependencies(this, aspect);    return ancestor.widget;  }  ...}
  • updateDependencies:流程终于残缺的跑通了!

    • updateDependencies办法调用了setDependencies办法
    • setDependencies办法,将子Widget的Element实例赋值给了继承InheritedElement的类的 _dependents 变量
class InheritedElement extends ProxyElement {  ...        @protected  void setDependencies(Element dependent, Object? value) {    _dependents[dependent] = value;  }        @protected  void updateDependencies(Element dependent, Object? aspect) {    setDependencies(dependent, null);  }  ...}
  • 看下图示:这图调了良久,不布局下,线很容易穿插,吐血...

自定义Builder

通过下面的剖析,Provider的widget定点刷新,曾经不再神秘了...

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

  • 自定义的EasyBuilder控件能起到和Consumer一样的刷新作用
class EasyBuilder<T> extends StatelessWidget {  const EasyBuilder(    this.builder, {    Key? key,  }) : super(key: key);  final Widget Function() builder;  @override  Widget build(BuildContext context) {    Provider.of<T>(context);    return builder();  }}
写下残缺的应用
  • view
class CustomBuilderPage extends StatelessWidget {  final provider = CustomBuilderProvider();  @override  Widget build(BuildContext context) {    return ChangeNotifierProvider(      create: (BuildContext context) => provider,      child: _buildPage(),    );  }  Widget _buildPage() {    return Scaffold(      appBar: AppBar(title: Text('Provider-自定义Builder范例')),      body: Center(        child: EasyBuilder<CustomBuilderProvider>(          () => Text(            '点击了 ${provider.count} 次',            style: TextStyle(fontSize: 30.0),          ),        ),      ),      floatingActionButton: FloatingActionButton(        onPressed: () => provider.increment(),        child: Icon(Icons.add),      ),    );  }}///自定义Builderclass EasyBuilder<T> extends StatelessWidget {  const EasyBuilder(    this.builder, {    Key? key,  }) : super(key: key);  final Widget Function() builder;  @override  Widget build(BuildContext context) {    Provider.of<T>(context);    return builder();  }}
  • provider
class CustomBuilderProvider extends ChangeNotifier {  int count = 0;  void increment() {    count++;    notifyListeners();  }}
  • 效果图

总结

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

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

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

MultiProvider

在下面的刷新机制外面,我说了一个:ChangeNotifierProvider这个类很重要,根本能够算是框架的主入口
  • 在这里,你可能有疑难了???

    • 这不对吧!
    • 咱们个别不是在main主入口的写全局Provider,要用到MultiProvider,按理说:主入口应该是MultiProvider!
void main() {  runApp(MyApp());}class MyApp extends StatelessWidget {  @override  Widget build(BuildContext context) {    return MaterialApp(builder: (BuildContext context, Widget? child) {      return MultiProvider(child: child, providers: [        //此处通过MultiProvider创立的Provider是全局的        ChangeNotifierProvider.value(value: ProSpanOneProvider()),      ]);    });  }}
  • 这里来看下MultiProvider代码(有限嵌套那个Provider就不讲了,很少用)

    • 源码so easy,继承Nested类,Nested能够优化一些布局嵌套问题,感兴趣的可查看:nested(pub)
    • 看源码,能够发现MultiProvider必定不是主入口,这中央只是将Provider的套在顶层Widget上
class MultiProvider extends Nested {  MultiProvider({    Key? key,    required List<SingleChildWidget> providers,    Widget? child,    TransitionBuilder? builder,  }) : super(          key: key,          children: providers,          child: builder != null              ? Builder(                  builder: (context) => builder(context, child),                )              : child,        );}
  • 下面的不是主入口,children外面用了ChangeNotifierProvider.value,来看看这个源码

    • ChangeNotifierProvider.value是ChangeNotifierProvider的命名构造函数,实际上ChangeNotifierProvider.value是对ChangeNotifierProvider应用的一个优化
class ChangeNotifierProvider<T extends ChangeNotifier?> extends ListenableProvider<T> {  ChangeNotifierProvider({    Key? key,    required Create<T> create,    bool? lazy,    TransitionBuilder? builder,    Widget? child,  }) : super(          key: key,          create: create,          dispose: _dispose,          lazy: lazy,          builder: builder,          child: child,        );  ChangeNotifierProvider.value({    Key? key,    required T value,    TransitionBuilder? builder,    Widget? child,  }) : super.value(          key: key,          builder: builder,          value: value,          child: child,        );  static void _dispose(BuildContext context, ChangeNotifier? notifier) {    notifier?.dispose();  }}
  • 为什么说ChangeNotifierProvider.value是对ChangeNotifierProvider应用的一个优化呢?

    • 来看看上面这个俩种写法,实际上等同的
void main() {  runApp(MyApp());}class MyApp extends StatelessWidget {  @override  Widget build(BuildContext context) {    return MaterialApp(builder: (BuildContext context, Widget? child) {      return MultiProvider(child: child, providers: [        //简化版        ChangeNotifierProvider.value(value: ProSpanOneProvider()),                  //成果和下面等同        ChangeNotifierProvider(create: (context) => ProSpanOneProvider()),      ]);    });  }}
  • 总结

    • 所以 ChangeNotifierProvider类是十分重要的,根本是Provider的主入口,没故障
    • 很多初始化的操作,都是借助从该类实例化的时候开始的

Consumer

Consumer应该是咱们日常,十分十分罕用的一个控件了,他的源码很简略,构造也很清晰

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

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

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

  • Consumer

    • 构造很清晰,继承了SingleChildStatelessWidget,重写了buildWithChild办法,在外面返回了builder函数
    • 请留神:这中央做了一个将child传到父类的操作;而且buildWithChild外面会传出一个child的,而后传到builder办法里
class Consumer<T> extends SingleChildStatelessWidget {  Consumer({    Key? key,    required this.builder,    Widget? child,  }) : super(key: key, child: child);  final Widget Function(BuildContext context, T value, Widget? child,) builder;  @override  Widget buildWithChild(BuildContext context, Widget? child) {    return builder(      context,      Provider.of<T>(context),      child,    );  }}
  • SingleChildStatelessWidget

    • 此处在形象了一个buildWithChild办法,而后在build办法中调用了buildWithChild办法
    • 此处,将context和咱们在内部传入的child,都传给了buildWithChild办法
    • ok,Consumer逻辑比较简单,大抵就这么多了!
abstract class SingleChildStatelessWidget extends StatelessWidget implements SingleChildWidget {  const SingleChildStatelessWidget({Key? key, Widget? child})      : _child = child,        super(key: key);  final Widget? _child;  Widget buildWithChild(BuildContext context, Widget? child);  @override  Widget build(BuildContext context) => buildWithChild(context, _child);  @override  SingleChildStatelessElement createElement() {    return SingleChildStatelessElement(this);  }}

Selector

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

    • 我这中央用了三层构造,将状态层解耦进来了
    • 对简单模块能更好应答
class ProHighCounterPage extends StatelessWidget {  final provider = ProHighCounterProvider();  @override  Widget build(BuildContext context) {    return ChangeNotifierProvider(      create: (BuildContext context) => provider,      child: _buildSelector(),    );  }  Widget _buildSelector() {    return Scaffold(      appBar: AppBar(title: Text('Provider-Extended范例')),      body: Center(        child: Selector(          shouldRebuild: (previous, next) {            return true;          },          selector: (context, provider) => provider,          builder: (_, __, ___) {            return Text('点击了 ${provider.state.count} 次',                style: TextStyle(fontSize: 30.0));          },        ),      ),      floatingActionButton: FloatingActionButton(        onPressed: () => provider.increment(),        child: Icon(Icons.add),      ),    );  }}class ProHighCounterProvider extends ChangeNotifier {  final state = ProExtendedCounterState();  void increment() {    state.count++;    notifyListeners();  }}class ProExtendedCounterState {  late int count;  ProExtendedCounterState() {    count = 0;  }}
  • Selector

    • 看来Selector0才是重点,去看看Selector0
class Selector<A, S> extends Selector0<S> {  Selector({    Key? key,    required ValueWidgetBuilder<S> builder,    required S Function(BuildContext, A) selector,    ShouldRebuild<S>? shouldRebuild,    Widget? child,  }) : super(          key: key,          shouldRebuild: shouldRebuild,          builder: builder,          selector: (context) => selector(context, Provider.of(context)),          child: child,        );}
Selector0:次要逻辑在_Selector0State中,上面三个断定为true,都能够使builder办法执行刷新操作
  1. oldWidget != widget:如果selector的父节点刷新了,builder也会刷新
  2. widget. _shouldRebuild != null && widget. _shouldRebuild!(value as T, selected):shouldRebuild回调实现了,且返回为true
  3. selector:selector回调返回了XxxProvider,XxxProvider这个实例齐全扭转了(例:从新实例化赋值);且shouldRebuild回调未实现
class Selector0<T> extends SingleChildStatefulWidget {  Selector0({    Key? key,    required this.builder,    required this.selector,    ShouldRebuild<T>? shouldRebuild,    Widget? child,  })  : _shouldRebuild = shouldRebuild,        super(key: key, child: child);  final ValueWidgetBuilder<T> builder;  final T Function(BuildContext) selector;  final ShouldRebuild<T>? _shouldRebuild;  @override  _Selector0State<T> createState() => _Selector0State<T>();}class _Selector0State<T> extends SingleChildState<Selector0<T>> {  T? value;  Widget? cache;  Widget? oldWidget;  @override  Widget buildWithChild(BuildContext context, Widget? child) {    final selected = widget.selector(context);    final shouldInvalidateCache = oldWidget != widget ||        (widget._shouldRebuild != null &&            widget._shouldRebuild!(value as T, selected)) ||        (widget._shouldRebuild == null &&            !const DeepCollectionEquality().equals(value, selected));    if (shouldInvalidateCache) {      value = selected;      oldWidget = widget;      cache = widget.builder(        context,        selected,        child,      );    }    return cache!;  }  @override  void debugFillProperties(DiagnosticPropertiesBuilder properties) {    super.debugFillProperties(properties);    properties.add(DiagnosticsProperty<T>('value', value));  }}

手搓一个状态治理框架

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

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

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

手搓状态框架

这个手搓框架做了很多简化,然而相对保留了原汁原味的Provider刷新机制!
  • ChangeNotifierEasyP:类比Provider的ChangeNotifierProvider

    • 代码做了大量的精简,只保留了provider的刷新机制的精华
    • 代码我就不解释了,下面的刷新机制如果看懂了,上面的代码很容易了解;如果没看懂,我解释上面代码也没用啊。。。
class ChangeNotifierEasyP<T extends ChangeNotifier> extends InheritedWidget {  ChangeNotifierEasyP({    Key? key,    Widget? child,    required this.create,  }) : super(key: key, child: child ?? Container());  final T Function(BuildContext context) create;  @override  bool updateShouldNotify(InheritedWidget oldWidget) => false;  @override  InheritedElement createElement() => EasyPInheritedElement(this);}class EasyPInheritedElement<T extends ChangeNotifier> extends InheritedElement {  EasyPInheritedElement(ChangeNotifierEasyP<T> widget) : super(widget);  bool _firstBuild = true;  bool _shouldNotify = false;  late T _value;  late void Function() callBack;  T get value => _value;  @override  void performRebuild() {    if (_firstBuild) {      _firstBuild = false;      _value = (widget as ChangeNotifierEasyP<T>).create(this);      _value.addListener(callBack = () {        // 解决刷新逻辑,此处无奈间接调用notifyClients        // 会导致owner!._debugCurrentBuildTarget为null,触发断言条件,无奈向后执行        _shouldNotify = true;        markNeedsBuild();      });    }    super.performRebuild();  }  @override  Widget build() {    if (_shouldNotify) {      _shouldNotify = false;      notifyClients(widget);    }    return super.build();  }  @override  void notifyDependent(covariant InheritedWidget oldWidget, Element dependent) {    //此处就间接刷新增加的监听子Element了,不各种super了    dependent.markNeedsBuild();    // super.notifyDependent(oldWidget, dependent);  }  @override  void unmount() {    _value.removeListener(callBack);    _value.dispose();    super.unmount();  }}
  • EasyP:类比Provider的Provider类
class EasyP {  /// 获取EasyP实例  /// 获取实例的时候,listener参数老是写错,这边间接用俩个办法辨别了  static T of<T extends ChangeNotifier>(BuildContext context) {    return _getInheritedElement<T>(context).value;  }  /// 注册监听控件  static T register<T extends ChangeNotifier>(BuildContext context) {    var element = _getInheritedElement<T>(context);    context.dependOnInheritedElement(element);    return element.value;  }  /// 获取间隔以后Element最近继承InheritedElement<T>的组件  static EasyPInheritedElement<T>      _getInheritedElement<T extends ChangeNotifier>(BuildContext context) {    var inheritedElement = context            .getElementForInheritedWidgetOfExactType<ChangeNotifierEasyP<T>>()        as EasyPInheritedElement<T>?;    if (inheritedElement == null) {      throw EasyPNotFoundException(T);    }    return inheritedElement;  }}class EasyPNotFoundException implements Exception {  EasyPNotFoundException(this.valueType);  final Type valueType;  @override  String toString() => 'Error: Could not find the EasyP<$valueType>';}
  • build:最初整一个Build类就行了
class EasyPBuilder<T extends ChangeNotifier> extends StatelessWidget {  const EasyPBuilder(    this.builder, {    Key? key,  }) : super(key: key);  final Widget Function() builder;  @override  Widget build(BuildContext context) {    EasyP.register<T>(context);    return builder();  }}

功败垂成,下面这三个类,就能起到和Provider一样的部分刷新性能!

刷新机制截然不同,相对没有吹牛皮!

上面来看看怎么应用吧!

应用

用法根本和Provider一摸一样...
  • view
class CounterEasyPPage extends StatelessWidget {  final easyP = CounterEasyP();  @override  Widget build(BuildContext context) {    return ChangeNotifierEasyP(      create: (BuildContext context) => easyP,      child: _buildPage(),    );  }  Widget _buildPage() {    return Scaffold(      appBar: AppBar(title: Text('自定义状态治理框架-EasyP范例')),      body: Center(        child: EasyPBuilder<CounterEasyP>(() {          return Text(            '点击了 ${easyP.count} 次',            style: TextStyle(fontSize: 30.0),          );        }),      ),      floatingActionButton: FloatingActionButton(        onPressed: () => easyP.increment(),        child: Icon(Icons.add),      ),    );  }}
  • easyP
class CounterEasyP extends ChangeNotifier {  int count = 0;  void increment() {    count++;    notifyListeners();  }}
  • 效果图:体验一下

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

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

总结

如果有靓仔的公司,不想应用第三方状态治理框架,齐全能够参照Provider的刷新机制,撸一个状态治理框架进去!我下面曾经撸了一个极简版,画龙画虎难画骨,下面我大抵把他的骨架整好了;如果有需要的话,施展你的聪明才智,copy过来给他填充血肉吧。。。

如果大家看懂了Provider的刷新机制,就会发现Provider状态框架,对系统资源占用极低,它仅仅只应用了ChangeNotifier,这仅仅是最根底的Callback回调,这会占用多少资源?刷新逻辑全是调用Flutte的framework层自带的那些api(获取InheritedElement的外部操作很简略,有趣味能够看看)。。。所以齐全不必放心,他会占用多少资源,简直忽略不计!

最初

一本秘籍

写完整篇文章,我忽然感觉本人把握一本文治秘籍!晓得了怎么去写出高端大气上档次且深奥的我的项目!

我当初就来传授给大家...

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

    • 如果要想十分深奥,深奥的本人都难以看懂,那间接滥用这种思维就稳了!
  • 多用各种设计模式,别和我扯什么简略易用,老夫写代码,就是设计模式一把梭,不论适合不适合,全怼下面

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

    • 不论那个零碎回调咱们懂不懂,都在外面整点代码,伪装很懂
    • 最要害的时候,零碎抽象类要继承,多写点本人的形象办法,千万不能写正文,不然当前本人看懂了,咋办?

以上纯属调侃

切勿对号入座进Provider,Provider相干思维用的张弛有度,他所形象的类,理论在多处实现了不同的实现类,大大的减少了扩大;而且他所继承的零碎上下文类里,所形象的办法,给了十分详尽的正文。

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

这是一个很优良的框架!

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

相干地址

  • 文章中Demo的Github地址:flutter_use
  • Web成果:https://cnad666.github.io/flu...

    • 如果provider相干性能按钮没看到,可能须要你清下浏览器缓存
  • Windows:Windows平台安装包

    • 明码:xdd666
系列文章
  • 源码篇:Handler那些事(万字图文)
  • 源码篇:ThreadLocal的奇思妙想(万字图文)