在之前我写过一篇文章,教你如何实现Flutter
的BLoC
框架(juejin.im/post/5cb80c… ),这个BLoC
的实现,模仿android
开发中的MVVM
开发方式,利用Flutter
的Stream
,在数据改变的时候,由Stream
推送数据给UI
层,而后UI
层自动更新UI
。此次咱们来本身实现一个Provider
,这个也是Flutter
中最经常使用的状态管理框架,由咱们本身实现Provider
,来了解Provider
内部核心原理。android
首先,在上一篇文章中(InheritWidget
原理解析:juejin.im/post/5edb97… ),咱们查看输出日志发现一个问题,就是点击“数字+1”这个按钮的时候,“数字+1”这个按钮也刷新了(日志输出CustomRaisedButton build
),这是由于咱们调用的setState
方法是BodyWidgetState
这个类的方法,因此BodyWidget
和它的child widget
都重建了,而咱们的需求是InheritedWidget
的数据改变的时候只刷新依赖此InheritedWidget
的widget
,要作到这一点,咱们就不能调用BodyWidgetState的setState
方法,而只调用InheritedWidget
上一个节点的setState
,也就是说要把InheritedWidget
做为一个StatefulWidget
的child
。而后咱们分步骤编写代码:缓存
InheritedWidget
成为可被监听的类型呢?这是由于InheritedWidget
只是提供数据,数据的消费者应该持有的是数据而不是InheritedWidget
,不然数据消费者若是持有InheritedWidget
的话,修改具体数据的方法就要添加到InheritedWidget
里,而数据类型是多种多样的,不可能所有写到InheritedWidget
里,因此咱们要建立可被监听的数据管理类,这样当数据发生变化的时候,调用数据管理类的方法,数据管理类再通知该类的监听者InheritedWidget
子类,用来保存数据管理类,该类能够在重建之后通知全部依赖了该类的widget
StatefulWidget
,这里咱们起名为ProviderCreator
,用来保存实际显示的Widget
和可被监听的数据管理类,并根据二者建立InheritedWidget
,并监听数据管理类的变化。这样能够在数据管理类中的数据发生变化的时候能够经过ProviderCreator
对应的State
调用setState
来让InheritedWidget
重建。InheritedWidget
重建时若是ProviderCreator
对应的Element
没有被销毁的话,那这个ProviderCreator
内部的可被监听的数据管理类和实际显示的child
就被缓存起来了(注意:这个child
是咱们传入的实际显示的widget
,而不是ProviderCreator
对应的State
的build
方法里返回的widget
)开始咱们的代码编写bash
建立InheritedWidget
子类的时候,里面的数据能够是任意类型,可是咱们须要在数据改变的时候通知监听者,因此咱们约束一下里面的数据类型必须是可被监听的类型,在flutter
里,有一个类叫作ChangeNotifier
,很是适合用来做为被监听者,代码以下app
class ChangeNotifier implements Listenable {
ObserverList<VoidCallback> _listeners = ObserverList<VoidCallback>();
@protected
bool get hasListeners {
return _listeners.isNotEmpty;
}
@override
void addListener(VoidCallback listener) {
_listeners.add(listener);
}
@override
void removeListener(VoidCallback listener) {
_listeners.remove(listener);
}
@mustCallSuper
void dispose() {
_listeners = null;
}
@protected
@visibleForTesting
void notifyListeners() {
if (_listeners != null) {
final List<VoidCallback> localListeners = List<VoidCallback>.from(_listeners);
for (final VoidCallback listener in localListeners) {
listener();
}
}
}
}
复制代码
代码我简化了一下,就是上面的样子,咱们的可被监听的数据类都须要继承该类框架
InheritedWidget
子类由于该类用来提供可被监听的数据管理类,因此起名叫`Provider`
复制代码
class Provider<T extends ChangeNotifier> extends InheritedWidget {
final T data;
Provider({Key key, this.data, Widget child}) : super(key: key, child: child) {
print("Provider=$hashCode");
}
//定义一个便捷方法,方便子树中的widget获取共享数据
static Provider<T> of<T extends ChangeNotifier>(BuildContext context, bool dependOn) {
if (dependOn) {
return context.dependOnInheritedWidgetOfExactType<Provider<T>>();
} else {
return context.getElementForInheritedWidgetOfExactType<Provider<T>>().widget as Provider<T>;
}
}
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
//在此简单返回true,则每次更新都会调用依赖其的子孙节点的'didChangeDependencies'。
return true;
}
}
复制代码
StatefulWidget
,用来保存实际显示的Widget
和可被监听的数据管理类,并根据二者建立InheritedWidget
,并监听数据管理类的变化。class ProviderCreator<T extends ChangeNotifier> extends StatefulWidget {
final T data;
final Widget child;
ProviderCreator({
Key key,
this.data,
this.child,
}) {
print("ProviderCreator=$hashCode");
}
@override
State<StatefulWidget> createState() {
return ProviderCreatorState<T>();
}
}
class ProviderCreatorState<T extends ChangeNotifier> extends State<ProviderCreator> {
void update() {
setState(() {});
}
@override
void initState() {
widget.data.addListener(update);
super.initState();
}
@override
void dispose() {
widget.data.dispose();
super.dispose();
}
@override
void didUpdateWidget(ProviderCreator<ChangeNotifier> oldWidget) {
//当Provider更新时,若是新旧数据不"==",则解绑旧数据监听,同时添加新数据监听
if (oldWidget.data != widget.data) {
oldWidget.data.dispose();
widget.data.addListener(update);
}
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
print("""CustomInheritedWidgetCreatorState build \twidget=${widget.hashCode} \twidget.data.hashCode=${widget.data.hashCode} \twidget.child=${widget.child.hashCode}""");
return Provider<T>(
data: widget.data,
child: widget.child,
);
}
}
复制代码
而后,咱们用一个示例来试一下咱们刚才本身写的Provider
咱们还用上篇文章里的示例,用一个计数器程序来测试。less
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter InheritWidget',
home: Scaffold(
appBar: AppBar(),
body: Center(
child: BodyWidget(),
),
),
);
}
}
class BodyWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return BodyWidgetState();
}
}
class BodyWidgetState extends State<BodyWidget> {
Counter counter = Counter();
@override
Widget build(BuildContext context) {
return ProviderCreator<Counter>(
data: counter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
//依赖
DependOnInheritedWidget<Counter>(),
//不依赖
Builder(builder: (context) {
return Text(Provider.of<Counter>(context, false).data.toString());
}),
Builder(builder: (context) {
return CustomRaisedButton(
onPressed: () {
//不依赖
Provider.of<Counter>(context, false).data.increment();
},
child: Text("数字+1"),
);
})
],
),
);
}
}
class Counter extends ChangeNotifier {
int num = 0;
void increment() {
num++;
notifyListeners();
}
@override
String toString() {
return "$num";
}
}
class DependOnInheritedWidget<T extends ChangeNotifier> extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return DependOnInheritedWidgetState<T>();
}
}
class DependOnInheritedWidgetState<T extends ChangeNotifier> extends State<DependOnInheritedWidget> {
@override
Widget build(BuildContext context) {
print("DependOnInheritedWidgetState build");
return Text(Provider.of<T>(context, true).data.toString());
}
@override
void didChangeDependencies() {
print("DependOnInheritedWidgetState didChangeDependencies");
super.didChangeDependencies();
}
}
class CustomRaisedButton extends RaisedButton {
const CustomRaisedButton({
@required VoidCallback onPressed,
Widget child,
}) : super(onPressed: onPressed, child: child);
@override
Widget build(BuildContext context) {
print("CustomRaisedButton build");
return super.build(context);
}
}
复制代码
当咱们点击“数字+1”这个按钮的时候,会在日志打印里发现以下信息:ide
I/flutter ( 489): CustomInheritedWidgetCreatorState build
I/flutter ( 489): widget=136741630
I/flutter ( 489): widget.data.hashCode=597399651
I/flutter ( 489): widget.child=443053943
I/flutter ( 489): Provider=611638398
I/flutter ( 489): DependOnInheritedWidgetState didChangeDependencies
I/flutter ( 489): DependOnInheritedWidgetState build
复制代码
说明CustomRaisedButton
再也不build
了,注意:Provider
的of
方法中的dependOn
参数,为true
说明调用了该方法的widget
依赖了InheritedWidget
,为false
就没有依赖InheritedWidget
,具体的能够看dependOnInheritedWidgetOfExactType
和getElementForInheritedWidgetOfExactType
这两个方法的源码,这里再也不赘述。post
至此,咱们作了一个简单的Provider
,大功告成!测试