前语
阅览此文的彦祖,亦菲们,附送一枚Provider模板代码生成插件!
我为啥要写这个插件呢?
此事说来话短,我这不预备写解析Provider源码的文章,必定要写这结构的运用样例啊,然后再哔哔源码呀!在写demo样例的时分,新建那俩三个文件、文件夹和必写的模板代码,这让我感到很方啊,这不耽搁我时刻嘛!然后就撸了这个插件,相对而言,多花了几百倍的时刻。。。
期望这个插件,能减轻运用Provider小伙们的一点工作量;插件里边的模板代码是经过我深思熟虑过的,假如各位靓仔有更好的模板代码,请在谈论里贴出来,我觉得合理的话,会加入到插件里。
关于Provider的源码,假如对规划形式或面向接口编程不熟悉的话,看起来是适当懵逼的,根本便是:懵逼树上懵逼果,懵逼树下你和我;Provider源码运用了很多的笼统类,调用父类结构函数,承继完成断语,许多要害的函数调用,点进去都是笼统类,有必要回来好几层去看看这个笼统类的完成类是什么,看的十分头大!这儿面有许多规划形式的痕迹:观察者形式、战略形式、外观形式、命令形式、访问者形式、模板形式、迭代器形式、、、
我会竭尽所能的将总体流程说清楚,相关不流畅流程会结合图文,并给出相应小demo演示
ε=(´ο`*)))唉,这篇文章写完,我感觉整个人都被掏空了。。。
不论你用或不用Provider,我相信在你读完本文的改写机制栏目,大概率会对该结构中闪耀的智慧,感到由衷的赞叹!
运用
老规矩,说原理之前,先来看下运用
Provider的运用,和我前俩篇写的Handler和ThreadLocal运用有一些区别
Provider是一个状况办理结构,写它的运用或许会占较多篇幅,所以文章全体篇幅也会较长,请见谅。。。
我真实不想分篇幅水赞啊,并且也是为了方便我们能够在一篇文章里边查阅相关常识(请结合旁边的大纲食用),也方便我随时修正优化文章内容。。。
插件
-
插件github:provider_template
- 运用中碰见什么bug,期望我们能及时给我提issue
-
插件能够进入Android Studio的Setting里边,挑选Plugins,然后查找flutter provider,第一个,看图上红框标定的便是了,点击install安装即可
- 来下看运用作用图
- 假如你不喜欢这种命名办法,这儿提供修正进口;也支撑了持久化
- 我们按需修正吧
- Alt + Enter : 能够挑选包裹Widget,有三种可选(Consumer、Selector、ChangeNotifirProvider),一键生成费事,重复且运用频率很高的Widget!
- 快捷代码片段提示:我自己写了三个,假如老哥们还有其它的骚操作,需求各位提PR啊
- 在这个文件里边增加就行了,我们能够参照写法:provider_template
- 输入 provider 前缀便有提示
初始写法
- 在写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(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代码
- get 流程
- 我们传入的create会直接赋值给 _value,现在这个 _value,便是我们在外面传进来的那个XxxProvider实例了!
- 底下也调用了 startListening,阐明从外面传进来的这个回调也调用了,将 上下文实例 和 传进来的XxxProvider实例 作为入参传进了这个回调中,此处传进来的回调也经过 .call 被调用了!
- dispose 流程
- 调用startListening办法时,该办法会回来一个移除监听Function
- 移除监听的Function在dispose时被调用,移除给XxxProvider增加的监听
- 从外部传入的dispose办法,也在此处被履行
- OK!收回资源的操作在此处都搞定了!
class _CreateInheritedProviderState<T> extends _DelegateState<T, _CreateInheritedProvider<T>> {
VoidCallback? _removeListener;
bool _didInitValue = false;
T? _value;
_CreateInheritedProvider<T>? _previousWidget;
@override
T get value {
...
if (!_didInitValue) {
_didInitValue = true;
if (delegate.create != null) {
assert(debugSetInheritedLock(true));
try {
...
_value = delegate.create!(element!);
} finally {
...
}
...
}
...
}
element!._isNotifyDependentsEnabled = false;
_removeListener ??= delegate.startListening?.call(element!, _value as T);
element!._isNotifyDependentsEnabled = true;
assert(delegate.startListening == null || _removeListener != null);
return _value as T;
}
@override
void dispose() {
super.dispose();
_removeListener?.call();
if (_didInitValue) {
delegate.dispose?.call(element!, _value as T);
}
}
...
}
- 要害的便是startListening回调了,来看下他的逻辑
- _startListening在此处 addListener 了!ChangeNotifier 是 Listenable 完成类,姑且把它当成访问者形式也可,所以这个value便是我们从外面传进来的 XxxProvider
- 回来了一个VoidCallback的Function,里边是移除监听逻辑
class ListenableProvider<T extends Listenable?> extends InheritedProvider<T> {
ListenableProvider({
Key? key,
required Create<T> create,
Dispose<T>? dispose,
bool? lazy,
TransitionBuilder? builder,
Widget? child,
}) : super(
key: key,
startListening: _startListening,
create: create,
dispose: dispose,
lazy: lazy,
builder: builder,
child: child,
);
...
static VoidCallback _startListening(InheritedContext e, Listenable? value,) {
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
}
还有终究一个问题!!!
需求调用_startListening办法,有必要调用 _CreateInheritedProviderState类里边的 get value
在哪个初始化进口,运用这个 get value 呢?
- 这儿直接给出定论了,仍是在 _InheritedProviderScopeElement这个上下文类里边
- reassemble:大局状况的初始化逻辑或热重载的时分被调用
- _delegateState首要在performRebuild回调中会赋初值
- 在reassemble回调中,_delegateState调用了value( _delegateState.value )
- 所以 get value 必定会在初始化的时分被调用,上面流程是通畅的
class _InheritedProviderScopeElement<T> extends InheritedElement
implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
late _DelegateState<T, _Delegate<T>> _delegateState;
...
@override
void performRebuild() {
if (_firstBuild) {
_firstBuild = false;
_delegateState = widget.owner._delegate.createState()..element = this;
}
super.performRebuild();
}
@override
void reassemble() {
super.reassemble();
final value = _delegateState.hasValue ? _delegateState.value : null;
if (value is ReassembleHandler) {
value.reassemble();
}
}
...
}
总结
上面剖析完了增加监听,以及相关的初始化链路和调用链路
- 能够把流程图整全了,来看看
改写逻辑
改写逻辑也是适当之绕啊;本菜比,各种debug,在framework里边各种打断点,总算把流程理通了!我忽然感觉自己打通了任督二脉!
作者为了完成这个改写逻辑,和体系api做了很多的交互,适当的精彩!
我会尽力将这个精彩纷呈的操作,展示给我们!
触发
- ListenableProvider
- 这当地逻辑很简略,增加了InheritedContext这个上下文类中的markNeedsNotifyDependents办法
- 阐明,我们在外部运用notifyListeners() 的时分,必定会触发InheritedContext完成类中的markNeedsNotifyDependents办法
class ListenableProvider<T extends Listenable?> extends InheritedProvider<T> {
ListenableProvider({
Key? key,
required Create<T> create,
Dispose<T>? dispose,
bool? lazy,
TransitionBuilder? builder,
Widget? child,
}) : super(
key: key,
startListening: _startListening,
create: create,
dispose: dispose,
lazy: lazy,
builder: builder,
child: child,
);
...
static VoidCallback _startListening(InheritedContext e, Listenable? value,) {
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
}
- _InheritedProviderScopeElement: _InheritedProviderScopeElement是InheritedContext的完成类
- 仍是要来这个类看看,只保留了和markNeedsNotifyDependents有关的代码
- markNeedsNotifyDependents回调作用,总的来说:会将强制依靠于T窗口小部件进行重建
- 说的这么笼统没啥用,下面会全面剖析,他是怎样做到让依靠于T窗口小部件进行重建的! 我想了下,仍是观察者形式的运用。。。
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
...
@override
void markNeedsNotifyDependents() {
if (!_isNotifyDependentsEnabled) {
return;
}
markNeedsBuild();
_shouldNotifyDependents = true;
}
...
}
改写流程
我们现在来理一下改写的流程!
- markNeedsNotifyDependents
- 当我们运用 notifyListeners(),就会触发,这个回调
- 此处调用了 markNeedsBuild(),然后给 _shouldNotifyDependents 设置为true
- 必备操作,来看下 markNeedsBuild() 作用
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
bool _shouldNotifyDependents = false;
...
@override
void markNeedsNotifyDependents() {
if (!_isNotifyDependentsEnabled) {
return;
}
markNeedsBuild();
_shouldNotifyDependents = true;
}
...
}
- markNeedsBuild
- _InheritedProviderScopeElement终究承继的仍是Element笼统类,markNeedsBuild()办法是Element中的
- Element类是一个完成了BuildContext笼统类中笼统办法的笼统类,该类十分重要
- 这个办法花里胡哨的代码写了一大堆,他最主要的功用:便是会调用Element的performRebuild()办法,然后触发ComponentElement的build()办法,终究触发_InheritedProviderScopeElement的build办法
- _InheritedProviderScopeElement extends InheritedElement extends ProxyElement extends ComponentElement extends Element
abstract class Element extends DiagnosticableTree implements BuildContext {
...
void markNeedsBuild() {
assert(_lifecycleState != _ElementLifecycle.defunct);
if (_lifecycleState != _ElementLifecycle.active)
return;
assert(owner != null);
assert(_lifecycleState == _ElementLifecycle.active);
assert(() {
if (owner!._debugBuilding) {
assert(owner!._debugCurrentBuildTarget != null);
assert(owner!._debugStateLocked);
if (_debugIsInScope(owner!._debugCurrentBuildTarget!))
return true;
if (!_debugAllowIgnoredCallsToMarkNeedsBuild) {
final List<DiagnosticsNode> information = <DiagnosticsNode>[
ErrorSummary('setState() or markNeedsBuild() called during build.'),
ErrorDescription(
'This ${widget.runtimeType} widget cannot be marked as needing to build because the framework '
'is already in the process of building widgets. A widget can be marked as '
'needing to be built during the build phase only if one of its ancestors '
'is currently building. This exception is allowed because the framework '
'builds parent widgets before children, which means a dirty descendant '
'will always be built. Otherwise, the framework might not visit this '
'widget during this build phase.',
),
describeElement(
'The widget on which setState() or markNeedsBuild() was called was',
),
];
if (owner!._debugCurrentBuildTarget != null)
information.add(owner!._debugCurrentBuildTarget!.describeWidget('The widget which was currently being built when the offending call was made was'));
throw FlutterError.fromParts(information);
}
assert(dirty); // can only get here if we're not in scope, but ignored calls are allowed, and our call would somehow be ignored (since we're already dirty)
} else if (owner!._debugStateLocked) {
assert(!_debugAllowIgnoredCallsToMarkNeedsBuild);
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('setState() or markNeedsBuild() called when widget tree was locked.'),
ErrorDescription(
'This ${widget.runtimeType} widget cannot be marked as needing to build '
'because the framework is locked.',
),
describeElement('The widget on which setState() or markNeedsBuild() was called was'),
]);
}
return true;
}());
if (dirty)
return;
_dirty = true;
owner!.scheduleBuildFor(this);
}
...
}
- build
- 这儿阐明下,这个子类调用父类办法,然后父类调用自身办法,是先触发这个子类的重写办法,然后能够经过 super. 的办法去履行父类逻辑
- 上面给_shouldNotifyDependents设置为true,所以build内部逻辑会履行notifyClients(widget)办法
- 接下来看下notifyClients(widget)办法
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
bool _shouldNotifyDependents = false;
...
@override
Widget build() {
if (widget.owner._lazy == false) {
value; // this will force the value to be computed.
}
_delegateState.build(
isBuildFromExternalSources: _isBuildFromExternalSources,
);
_isBuildFromExternalSources = false;
if (_shouldNotifyDependents) {
_shouldNotifyDependents = false;
notifyClients(widget);
}
return super.build();
}
...
}
- notifyClients:notifyClients()是InheritedElement类中的,notifyClients()办法是ProxyElement类中的一个笼统办法,InheritedElement在此处做了一个完成
-
notifyClients()是一个十分十分重要的办法,它内部有个for循环,遍历了_dependents这个HashMap类型的一切key值, _dependents的key是Element类型
- 什么是Element?它能够表示为Widget在树中特定位置的实例,一个Element能够构成一棵树(想想每个Container都有Element,然后其child再套其它的widget,这样就构成了一颗树)
- Element在此处将其理解为:自身Widget和其子节点构成的树,Element是这棵树的头结点,这特定位置的节点是实例化的,对这个特定位置的实例节点操作,会影响到他的子节点
- Widget的createElement()办法会实例化Element
- 这当地遍历_dependents的key取Element,能够猜想:他必定是想取某个元素或许说某个Widget
- 取到相关Element实例后,她会传入notifyDependent(oldWidget, dependent)办法中
- 接下来,需求看看notifyDependent(oldWidget, dependent)办法逻辑了
-
notifyClients()是一个十分十分重要的办法,它内部有个for循环,遍历了_dependents这个HashMap类型的一切key值, _dependents的key是Element类型
class InheritedElement extends ProxyElement {
final Map<Element, Object?> _dependents = HashMap<Element, Object?>();
...
@override
void notifyClients(InheritedWidget oldWidget) {
assert(_debugCheckOwnerBuildTargetExists('notifyClients'));
for (final Element dependent in _dependents.keys) {
assert(() {
// check that it really is our descendant
Element? ancestor = dependent._parent;
while (ancestor != this && ancestor != null)
ancestor = ancestor._parent;
return ancestor == this;
}());
// check that it really depends on us
assert(dependent._dependencies!.contains(this));
notifyDependent(oldWidget, dependent);
}
}
}
- notifyDependent
- if (dependencies is _Dependency) 这判别的逻辑题里边还有许多逻辑,是作者在BuildContext上面搞了一个select扩展办法(判别是否需求改写),但和现在讲了改写流程无关,我在里边绕了好久,凎!
- 去掉上面的逻辑就简略了,shouldNotify赋值为true,终究调用dependent.didChangeDependencies()
- dependent还记得是啥吗?是父类里边循环获得的Element实例
- 这当地直接去掉super操作,这也是体系主张的,我们能够重写notifyDependent办法,自界说相关逻辑;由于有时我们需求可挑选性的调用dependent.didChangeDependencies()!
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
...
@override
void notifyDependent(InheritedWidget oldWidget, Element dependent) {
final dependencies = getDependencies(dependent);
if (kDebugMode) {
ProviderBinding.debugInstance.providerDidChange(_debugId);
}
var shouldNotify = false;
if (dependencies != null) {
if (dependencies is _Dependency<T>) {
...
} else {
shouldNotify = true;
}
}
if (shouldNotify) {
dependent.didChangeDependencies();
}
}
...
}
- didChangeDependencies
- didChangeDependencies逻辑就很简略了,会调用markNeedsBuild()
- 能够理解为:终究会调用该Widget的build办法
- markNeedsBuild()就不讲了,内部触及逻辑太多了,还触及bind类,还会触及到制作流程,我嘞个去。。。
abstract class Element extends DiagnosticableTree implements BuildContext {
...
@mustCallSuper
void didChangeDependencies() {
assert(_lifecycleState == _ElementLifecycle.active); // otherwise markNeedsBuild is a no-op
assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));
markNeedsBuild();
}
...
}
现在有个超纠结的事情,这个点关乎整个改写流程的枢纽!
InheritedElement中的_dependents这个map的key是Element,这个Element是什么?上面一切流程都是为了调用 _dependents这个Map中key(Element)的markNeedsBuild()办法,终究是为了调用这个Element的Widget的build办法!
我们理解了吗?我们就算斗胆去蒙,去猜,去赌,这个Widget十有八九便是Consumer这类改写Widget啊!
可是!可是!他到底是怎样将这类改写Widget增加到InheritedElement的 _dependents变量中的呢 !?
- 上述流程图示
BuildContext
插播一个小常识点,这个常识和下述内容相关,这边先介绍一下
BuildContext是什么?
- BuildContext
- 每个笼统办法上面注释超级多,我删掉了(占篇幅),有兴趣的能够自己去源码里看看
- BuildContext便是笼统类,是约好好的一个笼统类,相关办法的功用现已被约好,你假如想完成这个笼统类类,相关办法功用完成能够有出入,但不应该违背笼统办法注释所描绘的功用范围
abstract class BuildContext {
Widget get widget;
BuildOwner? get owner;
bool get debugDoingBuild;
RenderObject? findRenderObject();
Size? get size;
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object aspect });
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({ Object? aspect });
InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>();
T? findAncestorWidgetOfExactType<T extends Widget>();
T? findAncestorStateOfType<T extends State>();
T? findRootAncestorStateOfType<T extends State>();
T? findAncestorRenderObjectOfType<T extends RenderObject>();
void visitAncestorElements(bool Function(Element element) visitor);
void visitChildElements(ElementVisitor visitor);
DiagnosticsNode describeElement(String name, {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty});
DiagnosticsNode describeWidget(String name, {DiagnosticsTreeStyle style = DiagnosticsTreeStyle.errorProperty});
List<DiagnosticsNode> describeMissingAncestor({ required Type expectedAncestorType });
DiagnosticsNode describeOwnershipChain(String name);
}
- StatelessWidget:看下StatelessWidget对BuildContext的完成(StatefulWidget同理,不贴了)
- 代码超级简略,StatelessWidget笼统了build办法,入参为BuildContext
- createElement()办法实例了StatelessElement类,并将StatelessWidget自身实例传入
- StatelessElement里边完成了ComponentElement的build办法:该办法调用了widget里边的build办法,并将自身的实例传入,流程通了,此处调用StatelessWidget的build办法,并传入了BuildContext的完成类
- ComponentElement的父类中必定有完成BuildContext,往上看看
abstract class StatelessWidget extends Widget {
const StatelessWidget({ Key? key }) : super(key: key);
@override
StatelessElement createElement() => StatelessElement(this);
@protected
Widget build(BuildContext context);
}
class StatelessElement extends ComponentElement {
StatelessElement(StatelessWidget widget) : super(widget);
@override
StatelessWidget get widget => super.widget as StatelessWidget;
@override
Widget build() => widget.build(this);
@override
void update(StatelessWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
_dirty = true;
rebuild();
}
}
- ComponentElement
- ComponentElement承继Element,它笼统了一个build办法,StatelessElement完成了这个办法,没毛病
- 来看看Element
abstract class ComponentElement extends Element {
...
@protected
Widget build();
...
}
- Element
- Element此处完成了BuildContext,所以承继他的子类,直接将自身实例传给BuildContext就OK了
- 假如没做什么骚操作,BuildContext能够理解为:每个Widget都有对应的Element( 经过createElement()生成 ),Element是BuildContext完成类
abstract class Element extends DiagnosticableTree implements BuildContext {
...
}
- Widget
- Widget笼统了一个createElement()办法
- 每个Widget的子类,理应都有自己对应的Element
@immutable
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key? key;
@protected
@factory
Element createElement();
...
}
- 图示
- 关于Widget和Element再多说俩句
知道为什么好多文章说Widget对Element是一对多吗?
首要Widget是Element的一个装备描绘,我们经过相似
StatelessElement createElement() => StatelessElement(this)
,将widget自身的装备信息实例传入XxxElemen(this)中,然后XxxElement能够经过传入的Widget装备信息去生成对应的Element实例我们发现没?每一个Widget都有对应的Element实例!
假设写了下面这个Widget
Widget _myWidget({Widget child}){ return Container(width:30, height:30, child:child); }
- 我们这样用
_myWidget( child: Container( child: _myWidget(), ) )
这不就对了嘛,只要一份Widget装备信息,可是会生成俩个Element!
可是仍是会有俩个Widget实例,但从装备信息层次上看,俩个Widget实例的装备信息都是相同的,所以是一份装备信息。。。
所以就有了Widget对Element是一对多的说法;反正我是这样理解的,仅供参考。。。
或许大佬们写文章,这些简略实例脑子自然生成,可是对这些没啥概念的靓仔,这或许就成了:一条定理或许既定概念
奇特的Provider.of()
为了将上面的流程连接起来,需求一位奇特的魔术师上台,下面就要请上我们的王炸:Provider.of() !
将改写组件增加到了InheritedElement中的_dependents变量里,他到底是怎样做到的呢?
- Provider.of() :下面便是该办法一切的逻辑,代码很少,完成的功用却很强!
- of办法中,会经过 _inheritedElementOf(context)办法获取到,和当时Widget间隔最近的(往父节点遍历)承继InheritedElement的XxxElement
- 上面是经过 _inheritedElementOf(context)办法中的 context.getElementForInheritedWidgetOfExactType()办法去获取的;承继InheritedElement的Widget的子节点,是能够经过这个办法去拿到间隔他最近的承继InheritedElement的Widget的XxxElement实例,相同的,也能够获取其间贮存的数据
- 你或许想,我拿到 承继InheritedElement的XxxElement的实例有啥?咱好好想想:我们拿到这个XxxElement实例后,我们不就能够往它的父类InheritedElement里边的 _dependents的map变量塞值了吗?狂喜…
- 它是怎样做到的呢?便是经过这个:context.dependOnInheritedElement(inheritedElement)
static T of<T>(BuildContext context, {bool listen = true}) {
...
final inheritedElement = _inheritedElementOf<T>(context);
if (listen) {
context.dependOnInheritedElement(inheritedElement);
}
return inheritedElement.value;
}
static _InheritedProviderScopeElement<T> _inheritedElementOf<T>(BuildContext context) {
...
_InheritedProviderScopeElement<T>? inheritedElement;
if (context.widget is _InheritedProviderScope<T>) {
context.visitAncestorElements((parent) {
inheritedElement = parent.getElementForInheritedWidgetOfExactType<
_InheritedProviderScope<T>>() as _InheritedProviderScopeElement<T>?;
return false;
});
} else {
inheritedElement = context.getElementForInheritedWidgetOfExactType<
_InheritedProviderScope<T>>() as _InheritedProviderScopeElement<T>?;
}
if (inheritedElement == null) {
throw ProviderNotFoundException(T, context.widget.runtimeType);
}
return inheritedElement!;
}
- 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的改写机制完好的说完了~~
撒花 ✿✿ヽ(°▽°)ノ✿
假如那里写的欠妥,请各位大佬不吝赐教 ~ . ~
手搓一个状况办理结构
看完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作用:cnad666.github.io/flutter_use…
- 假如provider相关功用按钮没看到,或许需求你清下浏览器缓存
- Windows:Windows渠道安装包
- 暗码:xdd666
系列文章
- 源码篇:Handler那些事(万字图文)
- 源码篇:ThreadLocal的奇思妙想(万字图文)