关于android:源码篇Flutter-Provider的另一面万字图文插件

5次阅读

共计 49966 个字符,预计需要花费 125 分钟才能阅读完成。

前言

浏览此文的彦祖,亦菲们,附送一枚 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 的逻辑
@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();}

  ...
}
  • 流程图示

_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
@immutable
abstract 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),
      ),
    );
  }
}

/// 自定义 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 的刷新机制残缺的说完了~~

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

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

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 的奇思妙想(万字图文)
正文完
 0