本身写一个Provider

在之前我写过一篇文章,教你如何实现FlutterBLoC框架(juejin.im/post/5cb80c… ),这个BLoC的实现,模仿android开发中的MVVM开发方式,利用FlutterStream,在数据改变的时候,由Stream推送数据给UI层,而后UI层自动更新UI。此次咱们来本身实现一个Provider,这个也是Flutter中最经常使用的状态管理框架,由咱们本身实现Provider,来了解Provider内部核心原理。android

首先,在上一篇文章中(InheritWidget原理解析:juejin.im/post/5edb97… ),咱们查看输出日志发现一个问题,就是点击“数字+1”这个按钮的时候,“数字+1”这个按钮也刷新了(日志输出CustomRaisedButton build),这是由于咱们调用的setState方法是BodyWidgetState这个类的方法,因此BodyWidget和它的child widget都重建了,而咱们的需求是InheritedWidget的数据改变的时候只刷新依赖此InheritedWidgetwidget,要作到这一点,咱们就不能调用BodyWidgetState的setState方法,而只调用InheritedWidget上一个节点的setState,也就是说要把InheritedWidget做为一个StatefulWidgetchild。而后咱们分步骤编写代码:缓存

  1. 建立可被监听的数据管理类,为何咱们不直接让InheritedWidget成为可被监听的类型呢?这是由于InheritedWidget只是提供数据,数据的消费者应该持有的是数据而不是InheritedWidget,不然数据消费者若是持有InheritedWidget的话,修改具体数据的方法就要添加到InheritedWidget里,而数据类型是多种多样的,不可能所有写到InheritedWidget里,因此咱们要建立可被监听的数据管理类,这样当数据发生变化的时候,调用数据管理类的方法,数据管理类再通知该类的监听者
  2. 建立InheritedWidget子类,用来保存数据管理类,该类能够在重建之后通知全部依赖了该类的widget
  3. 建立StatefulWidget,这里咱们起名为ProviderCreator,用来保存实际显示的Widget和可被监听的数据管理类,并根据二者建立InheritedWidget,并监听数据管理类的变化。这样能够在数据管理类中的数据发生变化的时候能够经过ProviderCreator对应的State调用setState来让InheritedWidget重建。InheritedWidget重建时若是ProviderCreator对应的Element没有被销毁的话,那这个ProviderCreator内部的可被监听的数据管理类和实际显示的child就被缓存起来了(注意:这个child是咱们传入的实际显示的widget,而不是ProviderCreator对应的Statebuild方法里返回的widget

开始咱们的代码编写bash

1. 建立可被监听的数据管理类

建立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();
      }
    }
  }
}
复制代码

代码我简化了一下,就是上面的样子,咱们的可被监听的数据类都须要继承该类框架

2. 建立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;
  }
}
复制代码

3. 建立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了,注意:Providerof方法中的dependOn参数,为true说明调用了该方法的widget依赖了InheritedWidget,为false就没有依赖InheritedWidget,具体的能够看dependOnInheritedWidgetOfExactTypegetElementForInheritedWidgetOfExactType这两个方法的源码,这里再也不赘述。post

至此,咱们作了一个简单的Provider,大功告成!测试

相关文章
相关标签/搜索