阅读此文的彦祖,亦菲们,附送一枚Provider模板代码生成插件!
我为啥要写这个插件呢?
此事说来话短,我这不准备写解析Provider源码的文章,肯定要写这框架的使用样例啊,然后再哔哔源码呀!在写demo样例的时候,新建那俩三个文件、文件夹和必写的模板代码,这让我感到很方啊,这不耽误我时间嘛!然后就撸了这个插件,相对而言,多花了几百倍的时间。。。
希望这个插件,能减轻使用Provider小伙们的一点工作量;插件里面的模板代码是经过我深思熟虑过的,如果各位靓仔有更好的模板代码,请在评论里贴出来,我觉得合理的话,会加入到插件里。
关于Provider的源码,如果对设计模式或面向接口编程不熟悉的话,看起来是相当懵逼的,基本就是:懵逼树上懵逼果,懵逼树下你和我;Provider源码使用了大量的抽象类,调用父类构造函数,继承实现断言,很多关键的函数调用,点进去都是抽象类,必须返回好几层去看看这个抽象类的实现类是什么,看的十分头大!这里面有很多设计模式的痕迹:观察者模式、策略模式、外观模式、命令模式、访问者模式、模板模式、迭代器模式、、、
我会竭尽所能的将总体流程说清楚,相关晦涩流程会结合图文,并给出相应小demo演示
ε=(´ο`*)))唉,这篇文章写完,我感觉整个人都被掏空了。。。
不管你用或不用Provider,我相信在你读完本文的刷新机制栏目,大概率会对该框架中闪耀的智慧,感到由衷的赞叹!
老规矩,说原理之前,先来看下使用
Provider的使用,和我前俩篇写的Handler和ThreadLocal使用有一些区别
Provider是一个状态管理框架,写它的使用可能会占较多篇幅,所以文章整体篇幅也会较长,请见谅。。。
我实在不想分篇幅水赞啊,而且也是为了方便大家可以在一篇文章里面查阅相关知识(请结合掘金旁边的大纲食用),也方便我随时修改优化文章内容。。。
ChangeNotifierProvider中为什么用builder?而不用child?
class ProEasyCounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) => ProEasyCounterProvider(),
builder: (context, child) {
return _buildPage(context);
},
);
}
Widget _buildPage(BuildContext context) {
final provider = context.read<ProEasyCounterProvider>();
return Scaffold(
appBar: AppBar(title: Text('Provider-Easy范例')),
body: Center(
child: Consumer<ProEasyCounterProvider>(
builder: (context, provider, child) {
return Text(
'点击了 ${provider.count} 次',
style: TextStyle(fontSize: 30.0),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => provider.increment(),
child: Icon(Icons.add),
),
);
}
}
class ProEasyCounterProvider extends ChangeNotifier {
int count = 0;
void increment() {
count++;
notifyListeners();
}
}
获取注入的实例的方法有点长;所以我在 _buildPage(...) 这个方法中,将其提出来,单独赋值给了一个变量,方便后续使用
插件生成代码分为俩个模式:Default和High
默认模式有俩个文件(Default):view、provider
高级模式有三个文件(High):view、provider、state
大家都是用Flutter的老手,对这种结构应该非常了解,state层是把数据层独立出来维护
在非常复杂的提交界面,state层我甚至还会分出:跳转(jump)、提交(submit)、展示(show)这三种结构;没办法,一个模块搞了上百个变量,不这样分,太难维护了
default:默认模式下的模板代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'provider.dart';
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) => CounterProvider(),
builder: (context, child) {
return _buildPage(context);
},
);
}
Widget _buildPage(BuildContext context) {
final provider = context.read<CounterProvider>();
return Container();
}
}
import 'package:flutter/material.dart';
class CounterProvider extends ChangeNotifier {
}
High:高级模式下的模板代码
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'provider.dart';
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) => CounterProvider(),
builder: (context, child) {
return _buildPage(context);
},
);
}
Widget _buildPage(BuildContext context) {
final provider = context.read<CounterProvider>();
return Container();
}
}
import 'package:flutter/material.dart';
import 'state.dart';
class CounterProvider extends ChangeNotifier {
final state = CounterState();
}
class CounterState {
CounterState() {
// init some variables
}
}
下面就是Provider的源码分析内容了,如果大家赶时间,可以点个赞(方便日后查阅,滑稽.jpg),回头等有时间,再静下心来慢慢看;我怕你快餐式阅读,读到刷新机制那块,会直接骂街,这写的啥玩意???
Provider的刷新机制,相关流程相当之绕,我已经竭尽全力,精简了无数我们不需要关注的代码,然后一步步带着你的思路去走一遍正确的流程,相关类还给了很多说明,但是架不住源码流程山路十八弯,绕的一比啊!你如果不用心去看,去体会,会相当烦躁。。。
我已经帮大家熬过最蛋筒的部分,相关绕的流程画了详细的图示,我已经努力了;如果你想知道Provider内部运转机制,现在就需要你努力了!
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
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中的控制器效果,每当控制器中的数值改变,其控件内容就自动更新
class TestNotifierController extends ChangeNotifier {
String _value = '0';
String get value => _value;
set value(String newValue) {
if (_value == newValue) return;
_value = newValue;
notifyListeners();
}
}
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(() {});
}
}
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()方法
void main(){
test();
test.call();
}
void test(){
print('test');
}
你可能想,这有什么用,我还多写一个 .call ?
来看下一个小范例,就知道这个东西能帮我们简化很多代码
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(),
);
}
}
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的应用,那肯定知道,这就是个观察者模式,但是问题是:它的监听在何处添加?添加的监听逻辑是否有完整的初始化链路?监听逻辑是什么?为什么触发监听逻辑,能导致相应控件刷新?
继承ChangeNotifier的类,是通过ChangeNotifierProvider传入到Provider内部,很明显ChangeNotifierProvider这个类很重要,基本可以算是框架的主入口
这边梳理下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,
);
...
static void _dispose(BuildContext context, ChangeNotifier? notifier) {
notifier?.dispose();
}
}
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);
}
}
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!,
);
}
}
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);
}
}
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方法,排除所有的测试类中使用的,然后断定我找对了,整个添加监听的链路是通顺的!
下面来整体的带大家过一遍源码
靓仔们,我要开始绕了!!!
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();
}
}
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);
}
}
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);
...
}
这地方会进行一个很重要的回溯流程,回溯到_InheritedProviderScopeElement
下次再有需要用到这个类,就直接拿这个类来讲了
@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();
}
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!,
);
}
}
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);
}
}
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();
}
...
}
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);
}
}
...
}
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}) {}
}
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();
}
...
}
不知道大家对这流程有没有个清晰的印象
有了上面分析出的element和_delegate不为空的,且 _delegate能直接访问 _CreateInheritedProvider这个实例基础,再来看下 _CreateInheritedProviderState代码
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);
}
}
...
}
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 呢?
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做了大量的交互,相当的精彩!
我会尽力将这个精彩纷呈的操作,展现给大家!
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);
}
}
class _InheritedProviderScopeElement<T> extends InheritedElement implements InheritedContext<T> {
_InheritedProviderScopeElement(_InheritedProviderScope<T> widget)
: super(widget);
...
@override
void markNeedsNotifyDependents() {
if (!_isNotifyDependentsEnabled) {
return;
}
markNeedsBuild();
_shouldNotifyDependents = true;
}
...
}
咱们现在来理一下刷新的流程!
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;
}
...
}
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);
}
...
}
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();
}
...
}
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);
}
}
}
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();
}
}
...
}
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是什么?
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);
}
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();
}
}
abstract class ComponentElement extends Element {
...
@protected
Widget build();
...
}
abstract class Element extends DiagnosticableTree implements BuildContext {
...
}
@immutable
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key? key;
@protected
@factory
Element createElement();
...
}
知道为什么好多文章说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是一对多的说法;反正我是这样理解的,仅供参考。。。
可能大佬们写文章,这些简单实例脑子自然生成,但是对这些没啥概念的靓仔,这或许就成了:一条定理或者既定概念
img
为了将上面的流程连接起来,需要一位神奇的魔术师登场,下面就要请上我们的王炸:Provider.of() !
将刷新组件添加到了InheritedElement中的_dependents变量里,他到底是怎么做到的呢?
static T of<T>(BuildContext context, {bool listen = true}) {
...
final inheritedElement = _inheritedElementOf<T>(context);
if (listen) {
context.dependOnInheritedElement(inheritedElement);
}
return inheritedElement.value;
}
static _InheritedProviderScopeElement<T> _inheritedElementOf<T>(BuildContext context) {
...
_InheritedProviderScopeElement<T>? inheritedElement;
if (context.widget is _InheritedProviderScope<T>) {
context.visitAncestorElements((parent) {
inheritedElement = parent.getElementForInheritedWidgetOfExactType<
_InheritedProviderScope<T>>() as _InheritedProviderScopeElement<T>?;
return false;
});
} else {
inheritedElement = context.getElementForInheritedWidgetOfExactType<
_InheritedProviderScope<T>>() as _InheritedProviderScopeElement<T>?;
}
if (inheritedElement == null) {
throw ProviderNotFoundException(T, context.widget.runtimeType);
}
return inheritedElement!;
}
context.getElementForInheritedWidgetOfExactType()
这个api是怎么拿到父节点的InheritedElement的呢?
abstract class Element extends DiagnosticableTree implements BuildContext {
...
@mustCallSuper
void mount(Element? parent, dynamic newSlot) {
...
_updateInheritance();
}
Map<Type, InheritedElement>? _inheritedWidgets;
...
@override
InheritedElement? getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {
assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T];
return ancestor;
}
void _updateInheritance() {
assert(_lifecycleState == _ElementLifecycle.active);
_inheritedWidgets = _parent?._inheritedWidgets;
}
...
}
class InheritedElement extends ProxyElement {
...
@override
void _updateInheritance() {
assert(_lifecycleState == _ElementLifecycle.active);
final Map<Type, InheritedElement>? incomingWidgets = _parent?._inheritedWidgets;
if (incomingWidgets != null)
_inheritedWidgets = HashMap<Type, InheritedElement>.from(incomingWidgets);
else
_inheritedWidgets = HashMap<Type, InheritedElement>();
_inheritedWidgets![widget.runtimeType] = this;
}
...
}
dependOnInheritedElement
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;
}
...
}
class InheritedElement extends ProxyElement {
...
@protected
void setDependencies(Element dependent, Object? value) {
_dependents[dependent] = value;
}
@protected
void updateDependencies(Element dependent, Object? aspect) {
setDependencies(dependent, null);
}
...
}
通过上面的分析,Provider的widget定点刷新,已经不再神秘了...
学以致用,咱们来整一个自定义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();
}
}
写下完整的使用
class CustomBuilderPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) => CustomBuilderProvider(),
builder: (context, child) {
return _buildPage(context);
},
);
}
Widget _buildPage(BuildContext context) {
final provider = context.read<CustomBuilderProvider>();
return Scaffold(
appBar: AppBar(title: Text('Provider-自定义Builder范例')),
body: Center(
child: EasyBuilder<CustomBuilderProvider>(
() => Text(
'点击了 ${provider.count} 次',
style: TextStyle(fontSize: 30.0),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => provider.increment(),
child: Icon(Icons.add),
),
);
}
}
///自定义Builder
class EasyBuilder<T> extends StatelessWidget {
const EasyBuilder(
this.builder, {
Key? key,
}) : super(key: key);
final Widget Function() builder;
@override
Widget build(BuildContext context) {
Provider.of<T>(context);
return builder();
}
}
class CustomBuilderProvider extends ChangeNotifier {
int count = 0;
void increment() {
count++;
notifyListeners();
}
}
以上,就将Provider的刷新机制完整的说完了~~
撒花 ✿✿ヽ(°▽°)ノ✿
如果那里写的欠妥,请各位大佬不吝赐教 ~ . ~
写完整篇文章,我突然感觉自己掌握一本武功秘籍!知道了怎么去写出高端大气上档次且深奥的项目!
我现在就来传授给大家...
以上纯属调侃
切勿对号入座进Provider,Provider相关思想用的张弛有度,他所抽象的类,实际在多处实现了不同的实现类,大大的增加了扩展;而且他所继承的系统上下文类里,所抽象的方法,给了非常详尽的注释。
从Provider的源码上看,能看出Provider的作者绝对是个高手,必须对framework层有足够了解,才能写出那样精彩的刷新机制!
这是一个很优秀的框架!
我为啥写上面这些调侃?ε=(´ο`*)))唉,前人练手,后人抓头。。。
系列文章
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。