Flutter 状态管理(数据共享)

所有程序里界面和数据的交互都至关重要,直接决定了整个程序的结构,选好状态管理方案的重要性就不言而喻了
目前为止,Flutter 里的状态管理有很多的实现方法,官方也给出了很多的案例

官方对state的图释

官方给出的参考举例

  • setState
  • ChangeNotifier
  • Delegate
  • scoped_model -InheritedWidget
  • Sigslot
  • provide
  • flutter-provide
  • rx dart, fish redux, bloc
  • EventBus

setState

最原始最基本 最重要的方式 setState,支持规模较小的程序足够了,其它方式最终都需要调用 setState

Function callback

Flutter 内置 ChangeNotifier, ValueNotifier 都可以认为是类似方案

Delegate

可以认为是多个回调函数,其他语言里都有类似模式,名称似乎来源于 Objective-C。

Sigslot

源自 Qt 里的经典编程模式,Dart 可以轻易实现。这种方式在 Flutter 里可能根本不会有太多应用

pkg:scoped_model

个人以为是最佳方案,源自 Fuchsia 代码,在其中广泛使用,设置程序几乎都是这个模式,后来独立为 package,包括注释也只有 287 行代码。由于 Fuchsia App 结构都是后台Service+前台UI,这个方案绝对是最合适的方案。使用 InheritedWidget 实现,性能不可能更好。

pkg:provide

出自Flutter dev team,绝对的官方了,总共代码 675行。实现方式和 scoped_model 类似,增加 Providers,Provider 支持 Stream。

flutter-provide

可以认为这个比 provide 更早,功能更丰富,实现依然是 InheritedWidget。可能不会有太广泛使用,但是在时间上有历史意义,故列出。

rxdart, fish-redux,bloc

略……^ _ ^

EventBus

分享主体:

InheritedWidget

可能对InheritedWidget 比较陌生,但是在Flutter开发当中,我们几乎每个Page里都能看到的身影,并且用过它,,它可以高效的将数据在Widget树中向下传递、共享,这在一些需要在Widget树中共享数据的场景中非常方便,如Flutter中,正是通过InheritedWidget来共享应用主题(Theme)和Locale(当前语言环境)信息的。它是自上而下的

如:

 MediaQuery.of(context).size.width
 Theme.of(context).snackBarTheme.actionTextColor

使用姿势

  final InheritedWidgetModel model;

  //点击+号的方法
  final Function() increment;

  //点击-号的方法
  final Function() reduce;

  const MainInheritedWidget({Key key, Widget child, this.model, this.increment, this.reduce})
      : super(key: key, child: child);

  static MainInheritedWidget of(BuildContext context) {
    context.dependOnInheritedWidgetOfExactType();
//    context.inheritFromWidgetOfExactType(MainInheritedWidget);
  }

  @override
  bool updateShouldNotify(MainInheritedWidget oldWidget) {
    return oldWidget.model != model;
  }

触发事件

//触发,完全是自定义
 MainInheritedWidget.of(context).increment();
//取数据
Text( "${MainInheritedWidget.of(context).model.count}",style: TextStyle(fontSize: 50 ,fontWeight: FontWeight.w900),),

scoped_model

短小精干的scoped_model,是以InheritedWidget为基础的开发,所以直接展示,它的读取在一个函数体里去操作

class Counter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScopedModelDescendant(
      builder: (context, _, model) => ActionChip(
        label: Text('${model.count}'),//可以直接取
        onPressed: model.increaseCount,//可以直接改变
      ),
    );
  }
}

ChangeNotifier

通知Notification的发送是通过disPatch进行分发的,就好像Android里面的事件分发,当NotificationListener监听到了通知事件,这时候会走到其onNotification回调中,根据回调中的返回值类型(true还是false)来决定是否还继续向父亲节点发送通知。它是自下而上。

接受数据

NotificationListener(
        onNotification: (notification) {
          setState(() {
            count = notification.count;
          });
          return true;
        },

发送数据

 TestNotification(count: count).dispatch(context);

我们需要注意的地方:

  Builder(
    builder: (context) {
      return RaisedButton(
        color: Colors.blue,
        child: Text('+'),
        onPressed: () {
          count++;
          TestNotification(count: count).dispatch(context);
        },
      );
    },
  )

为什么我们一定要用Builder 取构建一下?
原因是通知在分发的时候,需要一个context参数,这个参数指的是Notification监听的子widget的context,如果直接的话,context是根widget的,这样会导致监听不到子widget了。
所以需要我们通过Builder构建出我们子widget的context,

Provide

和scoped_model一样,Provide也是借助了InheritWidget,将共享状态放到顶层MaterialApp之上。底层部件通过Provier获取该状态,并通过混合ChangeNotifier通知依赖于该状态的组件刷新。Provide还提供了Provide.stream,让我们能够以处理流的方式处理数据

直接上才艺:

void main() {
 var counter = ProvideCounterModel();
 var providers = Providers();
 providers..provide(Provider.value(counter));
 runApp(ProviderNode(
   child: ProvideApp(),
   providers: providers,
 ));

接受数据:

child: Provide(
 builder: (context, child, counter) {
   return Text(
     "${counter.count}",
     style: TextStyle(fontSize: 50, fontWeight: FontWeight.w900),
   );
 },
)

发送数据:

RaisedButton(
    color: Colors.blue,
    child: Text('+'),
    onPressed: () {
      Provide.value(context).increment();
    },
  )

EventBus

在APP中,我们经常会需要一个广播机制,用以跨页面事件通知,Flutter中我们可以使用event_bus提供的事件总线功能来实现一些状态的更新,其核心是基于Dart Streams(流);事件总线通常实现了订阅者模式,订阅者模式包含发布者和订阅者两种角色,可以通过事件总线来触发事件和监听事件

EventBus才艺展示

import 'package:event_bus/event_bus.dart';

EventBus eventBus = new EventBus();


class CounterEvent {
  int count;

  CounterEvent({this.count});
}

接受数据

  @override
  void initState() {
    super.initState();
    print("initState");
    subscription = eventBus.on().listen((event) {
      setState(() {
        count = event.count;
      });
    });
  }

  @override
  void dispose() {
    print("dispose");
    if (subscription != null) {
      subscription.cancel();
    }
    super.dispose();
  }

发送数据

RaisedButton(
color: Colors.blue,
child: Text('+'),
onPressed: () {
  count ++;
  eventBus.fire(CounterEvent(count: count));
},
)

你可能感兴趣的:(Flutter 状态管理(数据共享))