专栏首页每天学点Android知识Flutter状态管理(2)——单Stream和广播Stream

Flutter状态管理(2)——单Stream和广播Stream

Flutter状态管理(1)——InheritedWidget中介绍了状态管理以及如何使用InheritedWidget来实现全局状态的管理。这篇博客将介绍如何使用Stream来实现状态管理。

Stream是一种流,在dart中用于异步产生数据,分为两种类型:单订阅Stream和广播Stream。单订阅Stream只允许在该Stream的整个生命周期内使用单个监听器,即使第一个subscription被取消了,也无法在这个流上监听到第二次事件;而广播Stream允许任意个数的subscription,可以随时随地给它添加subcontractor,只要新的监听开始工作流,它就能收到新的事件。

单Stream

Flutter中的StreamBuilder组件封装了Stream,可以根据不同的状态创建不同的Widget。

下面以一个异步加载网络数据的例子来展示:

class SingleStreamPage extends StatelessWidget {

  StreamController<String> stream = StreamController();

  @override
  Widget build(BuildContext context) {

    doNetWork();

    return Scaffold(
        appBar: AppBar(
          title: Text('单Stream'),
        ),
        body: Center(
          child: StreamBuilder<String>(
            builder: (context, snapshot) {
              if (snapshot == null || !snapshot.hasData) {
                return CircularProgressIndicator();
              } else {
                return Text(snapshot.data);
              }
            },
            stream: stream.stream,
          ),
        ));
  }

  void doNetWork() {
    Future.delayed(Duration(seconds: 5), () {
      stream.add('hello world');
    });
  }
}

这里创建一个StreamController,模拟了一个网络耗时操作,等待5s后,往流中添加一个数据,那么StreamBuilder函数将会收到数据,显示文本,而一开始没有收到数据,就会显示菊花。

这种单Stream可以在一个页面中控制状态,因为只能有一个订阅者,因此只能做局部状态的控制。

广播Stream

广播Stream,可以有多个订阅者,当发布一个事件后,存在的多个订阅者就都可以收到消息。

这边举个例子:PageA根据数字计算其平方,PageB根据数字计算其立方,PageC负责发送数据。页面间的关系是PageA-->PageB-->PageC。

接收数据的页面

class PageA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('平方页面'),
      ),
      body: Container(
        child: Column(
          children: <Widget>[
            RaisedButton(
              onPressed: () {
                Navigator.of(context)
                    .push(MaterialPageRoute(builder: (context) {
                  return PageB();
                }));
              },
              child: Text('To Page B'),
            ),
            StreamBuilder<int>(
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Text('${snapshot.data * snapshot.data}');
                } else {
                  return Text('no data');
                }
              },
              stream: StateSubject().streamController.stream,
            )
          ],
        ),
      ),
    );
  }
}

可以看到,接收和单Stream是一样的。

发射数据

class PageC extends StatelessWidget {
  int num = 1;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('发射数据页面'),
      ),
      body: Container(
        child: Column(
          children: <Widget>[
            RaisedButton(
              onPressed: () {
                StateSubject().update(num++);
              },
              child: Text('发射数据'),
            ),
          ],
        ),
      ),
    );
  }
}

点击将会发送一个数据。

广播Stream

class StateSubject {
  static final StateSubject _instance = StateSubject._();

  factory StateSubject() => StateSubject._instance;

  StreamController<int> streamController;

  StateSubject._() {
    streamController = StreamController.broadcast();
  }

  void update(int num) {
    streamController.sink.add(num);
  }
}

可以看到与单Stream的区别是使用了broadcast()构造方法创建的就会是广播Stream。

使用Stream进行全局状态的管理,有很大的局限性。因为这依赖于监听者的存在,而如果这个监听的页面还没出现或不在内存中,那么该页面的数据从哪里来呢?因为Stream是一旦消耗就没有了,因此如果那些还未出现的页面想消费一个已发送的事件,那只能是找某种方式将事件保存下来。这又会很麻烦,看来Stream的方式并不适合用在状态管理。

参考

  • Using StreamBuilder in Flutter
  • Flutter中的状态管理

本文分享自微信公众号 - 每天学点Android知识(android_every_day),作者:星风coder

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • EventBus线程分发

    EventBus支持线程分发,在上一篇博客EventBus简介以及初步使用中,了解到EventBus的使用主要涉及事件发送者,以及事件订阅者;对于发送和订阅这两...

    用户1108631
  • 从0到1实现一个Android路由(1)——初探路由

    什么是路由?最初接触路由是在大学计算机网络中,网络层IP报文传输会涉及一个路由表的概念,路由表由源IP、目的IP组成,起始就是一个映射表。Android路由也是...

    用户1108631
  • EventBus源码分析之发布流程

    继上篇文章EventBus源码分析之订阅流程之后,继续介绍EventBus的发布,事件发送完,EventBus如何做到调用之前注册的方法。

    用户1108631
  • Flutter完整开发实战详解(十一、全面深入理解Stream)

    Stream 在 Flutter 是属于非常关键的概念,在 Flutter 中,状态管理除了 InheritedWidget 之外,无论 rxdart,Bloc...

    GSYTech
  • 第二课:linux设备树的规范(dts和dtb)

    转载请注明文章地址 http://wiki.100ask.org/Linux_devicetree

    韦东山
  • Java8 Lambda表达式与Stream API (二): Stream API的使用你要知道的Java8 匿名内部类、函数式接口、lambda表达式与Stream API都在这里

    你要知道的Java8 匿名内部类、函数式接口、lambda表达式与Stream API都在这里 转载请注明出处 https://cloud.tencent.co...

    WWWWDotPNG
  • 基于大数据的用户行为预测

    随着智能手机的普及和APP形态的愈发丰富,移动设备的应用安装量急剧上升。用户在每天使用这些APP的过程中,也会产生大量的线上和线下行为数据。这些数据反映了用户的...

    个推君
  • kafka配置目录树

    最近没那么忙,抽点时间整理下kafka的知识,以下是kafka存储在zookeeper上的配置目录树

    codingforfun
  • 使用Keepalived实现MySQL主从高可用

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.n...

    用户1148526
  • MyCAT集群在线扩容的场景小结

    最近线上有一套集群的存储存在瓶颈,导致经常会有报警,如果按照存储现状和稍后的假期的数据增长,很可能会带来一些意料之外的问题,所以整体评估后,决定对已有的集群...

    jeanron100

扫码关注云+社区

领取腾讯云代金券