flutter开发实战-StreamBuilder使用介绍及实例

flutter开发实战-StreamBuilder使用介绍及实例

StreamBuilder是一个Widget,它依赖Stream来做异步数据获取刷新widget。

一、Stream

Stream是一种用于异步处理数据流的机制,它允许我们从一段发射一个事件,从另外一段去监听事件的变化.Stream类似于JavaScript中的Promise、Swift中的Future或Java中的RxJava,它们都是用来处理异步事件和数据的。Stream是一个抽象接口,我们可以通过StreamController接口可以方便使用Stream。

  • StreamController 流控制器

通过StreamController,我们可以监听暂停、恢复、取消、完成、错误等事件

 final streamController = StreamController(
   onPause: () => print('Paused'),
   onResume: () => print('Resumed'),
   onCancel: () => print('Cancelled'),
   onListen: () => print('Listens'),
 );

 streamController.stream.listen(
   (event) => print('Event: $event'),
   onDone: () => print('Done'),
   onError: (error) => print(error),
 );
  • StreamSink 用作发射事件

StreamSink可以通过streamController获取,streamController.sink。
StreamSink发射事件调用add方法

  • Stream 用作事件的监听

Stream 可以通过streamController获取,streamController.stream
Stream 监听则可以调用listen方法

  • StreamSubscription 用作管理监听,关闭、暂停等

streamSubscription 通过Stream调用listen获取。streamSubscription有暂停、恢复、关闭、取消等方法。

二、Stream的使用

Stream使用的步骤如下

  /// 获取StreamSubscription用作管理监听,关闭暂停等
  StreamSubscription<int>? subscription;

  /// StreamController
  StreamController<int>? streamController = StreamController<int>();

  /// StreamSink用作发射事件
  StreamSink<int>? get streamSink => streamController?.sink;

  /// 获取Stream用作事件监听
  Stream<int>? get streamData => streamController?.stream;

  /// 使用subscription来监听事件
  subscription = streamData?.listen((event) {
    // TODO
    print("subscription listen event:${event}");
  });

  // 发射一个事件
  streamSink?.add(index);
    

Stream使用实例完整代码如下

import 'dart:async';

import 'package:flutter/material.dart';

class SteamDemoPage extends StatefulWidget {
  const SteamDemoPage({super.key});

  @override
  State<SteamDemoPage> createState() => _SteamDemoPageState();
}

class _SteamDemoPageState extends State<SteamDemoPage> {
  int index = 0;
  int listenData = 0;

  /// 获取StreamSubscription用作管理监听,关闭暂停等
  StreamSubscription<int>? subscription;

  /// StreamController
  StreamController<int>? streamController = StreamController<int>();

  /// StreamSink用作发射事件
  StreamSink<int>? get streamSink => streamController?.sink;

  /// 获取Stream用作事件监听
  Stream<int>? get streamData => streamController?.stream;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    streamController = StreamController<int>();

    /// 使用subscription来监听事件
    subscription = streamData?.listen((event) {
      // TODO
      print("subscription listen event:${event}");
      setState(() {
        listenData = event;
      });
    });

    // 发射一个事件
    streamSink?.add(index);
    index++;
  }

  void testStream(BuildContext context) {
    // 发射一个事件
    streamSink?.add(index);
    index++;
    print("index -- ${index}");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('HeroPage'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Text(
              '监听的listenData:${listenData}',
              style: TextStyle(
                fontSize: 16,
                color: Colors.black87,
              ),
            ),
            SizedBox(height: 30,),
            TextButton(
              onPressed: () {
                testStream(context);
              },
              child: Container(
                height: 46,
                width: 150,
                color: Colors.lightBlue,
                alignment: Alignment.center,
                child: Text(
                  '测试Stream',
                  style: TextStyle(
                    fontSize: 14,
                    color: Colors.white,
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
    

最后可以看到效果图,当点击按钮时候,监听的数值更新。
在这里插入图片描述

三、StreamBuilder

既然使用了Stream,我们可以StreamBuilder。如果我们再使用setState来刷新,则没有必要使用Stream了。

StreamBuilder是Flutter框架中的一个内置小部件,它可以监测数据流(Stream)中数据的变化,并在数据发生变化时重新构建小部件树。

在StreamBuilder中,当数据流发生变化,Flutter框架会自动传递一个AsyncSnapshot,AsyncSnapshot对象包含Stream中的最新数据以及其他有关数据流信息,如是否处理链接状态、错误信息等。

StreamBuilder(
              stream: streamData,
              builder: (BuildContext ctx, AsyncSnapshot snapshot) {
                if (!snapshot.hasData) {
                  return Text("没有数据");
                } else {
                  return Text(
                         '监听的listenData:${snapshot.data}',
                         style: TextStyle(
                           fontSize: 16,
                           color: Colors.black87,
                         ),
                       );
                }
              },
            ),
    

StreamBuilder的构造方法如下

const StreamBuilder({
    super.key,
    this.initialData,
    super.stream,
    required this.builder,
  }) : assert(builder != null);
    
  • initialData : 默认初始化数据
  • stream : stream事件流对象
  • builder : 负责根据不同状态创建对应ui的方法实现

StreamBuilder中的其他方法

  • afterConnected:返回一个AsyncSnapshot,当订阅了stream时会回调此AsyncSnapshot
  • afterData:返回一个AsyncSnapshot,当stream有事件触发时会回调此AsyncSnapshot
  • afterDisconnected:返回一个AsyncSnapshot,当取消订阅stream时会回调此AsyncSnapshot
  • afterDone:返回一个AsyncSnapshot,当stream被关闭时会回调此AsyncSnapshot
  • afterError:返回一个AsyncSnapshot,stream发生错误时会回调此AsyncSnapshot

四、使用StreamBuilder示例

在上面的示例中,我们可以将Text这个Widget通过StreamBuilder来包裹一下。
代码如下

StreamBuilder(
              stream: streamData,
              builder: (BuildContext ctx, AsyncSnapshot snapshot) {
                if (!snapshot.hasData) {
                  return Text("没有数据");
                } else {
                  return Text(
                         '监听的listenData:${snapshot.data}',
                         style: TextStyle(
                           fontSize: 16,
                           color: Colors.black87,
                         ),
                       );
                }
              },
            ),
    

这里可以将示例中的StreamSubscription移除,暂时用不到了,可以找到StreamBuilder继承的StreamBuilderBase中已经创建了StreamSubscription,并且_subscribe

/// State for [StreamBuilderBase].
class _StreamBuilderBaseState<T, S> extends State<StreamBuilderBase<T, S>> {
  StreamSubscription<T>? _subscription; // ignore: cancel_subscriptions
  late S _summary;

....

void _subscribe() {
    if (widget.stream != null) {
      _subscription = widget.stream!.listen((T data) {
        setState(() {
          _summary = widget.afterData(_summary, data);
        });
      }, onError: (Object error, StackTrace stackTrace) {
        setState(() {
          _summary = widget.afterError(_summary, error, stackTrace);
        });
      }, onDone: () {
        setState(() {
          _summary = widget.afterDone(_summary);
        });
      });
      _summary = widget.afterConnected(_summary);
    }
  }

  void _unsubscribe() {
    if (_subscription != null) {
      _subscription!.cancel();
      _subscription = null;
    }
  }

    

使用StreamBuilder完整示例代码如下

import 'dart:async';

import 'package:flutter/material.dart';

class SteamDemoPage extends StatefulWidget {
  const SteamDemoPage({super.key});

  @override
  State<SteamDemoPage> createState() => _SteamDemoPageState();
}

class _SteamDemoPageState extends State<SteamDemoPage> {
  int index = 0;
  int listenData = 0;

  /// 获取StreamSubscription用作管理监听,关闭暂停等
  // StreamSubscription<int>? subscription;

  /// StreamController
  StreamController<int>? streamController = StreamController<int>();

  /// StreamSink用作发射事件
  StreamSink<int>? get streamSink => streamController?.sink;

  /// 获取Stream用作事件监听
  Stream<int>? get streamData => streamController?.stream;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    streamController = StreamController<int>();

    /// 使用subscription来监听事件
    // subscription = streamData?.listen((event) {
    //   // TODO
    //   print("subscription listen event:${event}");
    //   setState(() {
    //     listenData = event;
    //   });
    // });

    // 发射一个事件
    streamSink?.add(index);
    index++;
  }

  void testStream(BuildContext context) {
    // 发射一个事件
    streamSink?.add(index);
    index++;
    print("index -- ${index}");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('HeroPage'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            StreamBuilder(
              stream: streamData,
              builder: (BuildContext ctx, AsyncSnapshot snapshot) {
                if (!snapshot.hasData) {
                  return Text("没有数据");
                } else {
                  return Text(
                         '监听的listenData:${snapshot.data}',
                         style: TextStyle(
                           fontSize: 16,
                           color: Colors.black87,
                         ),
                       );
                }
              },
            ),
            SizedBox(
              height: 30,
            ),
            TextButton(
              onPressed: () {
                testStream(context);
              },
              child: Container(
                height: 46,
                width: 150,
                color: Colors.lightBlue,
                alignment: Alignment.center,
                child: Text(
                  '测试Stream',
                  style: TextStyle(
                    fontSize: 14,
                    color: Colors.white,
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

    

https://brucegwo.blog.csdn.net/article/details/136232000

五、小结

flutter开发实战-StreamBuilder使用介绍及实例。

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/403620.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTTP 与 HTTPS-HTTP 解决了 HTTP 哪些问题?

资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) HTTP 解决了 HTTP 哪些问题? HTTP 由于是明文传输&#xff0c;所以安全上存在以下三个风险: 窃听风险&#xff0c;比如通信链路上可以获取通信内容&#xff0c;用户号容易没。篡改风险&#xff0c;比如…

Vue 图片轮播第三方库 介绍

Vue图片轮播是一种在网页上以自动或手动方式展示图片的组件&#xff0c;常用于产品展示、网站banner等场景。有许多第三方库可以帮助Vue开发者轻松实现图片轮播功能。以下是一些流行的Vue图片轮播第三方库的介绍&#xff1a; 1. Vue-awesome-swiper - **简介**&#xff1a;V…

Spring Cloud Alibaba-05-Gateway网关-03-过滤器(Filter)使用

Lison <dreamlison163.com>, v1.0.0, 2023.10.20 Spring Cloud Alibaba-05-Gateway网关-03-过滤器(Filter)使用 文章目录 Spring Cloud Alibaba-05-Gateway网关-03-过滤器(Filter)使用过滤器的简介什么是过滤器&#xff1f;过滤器的生命周期过滤器的分类和作用范围 局部…

从 Elasticsearch 到 Apache Doris,统一日志检索与报表分析,360 企业安全浏览器的数据架构升级实践

导读&#xff1a;随着 360 企业安全浏览器用户规模的不断扩张&#xff0c;浏览器短时间内会产生大量的日志数据。为了提供更好的日志数据服务&#xff0c;360 企业安全浏览器设计了统一运维管理平台&#xff0c;并引入 Apache Doris 替代了 Elasticsearch&#xff0c;实现日志检…

HarmonyOS4.0系统性深入开发36 媒体查询(mediaquery)

媒体查询&#xff08;mediaquery&#xff09; 概述 媒体查询作为响应式设计的核心&#xff0c;在移动设备上应用十分广泛。媒体查询可根据不同设备类型或同设备不同状态修改应用的样式。媒体查询常用于下面两种场景&#xff1a; 针对设备和应用的属性信息&#xff08;比如显…

Prometheus+Grafana 监控

第1章Prometheus 入门 Prometheus 受启发于 Google 的 Brogmon 监控系统&#xff08;相似的 Kubernetes 是从 Google的 Brog 系统演变而来&#xff09;&#xff0c;从 2012 年开始由前 Google 工程师在 Soundcloud 以开源软件的形式进行研发&#xff0c;并且于 2015 年早期对外…

【FPGA】VHDL:小型出勤系统设计

附源代码&#xff0c;一定能实现&#xff01; 目录 EDA设计练习题&#xff1a; 实验要求如下&#xff1a; 思路分析&#xff1a; 代码 99进制计数器 码转换 顶层文件 特别注意 测试 编译通过 结果展示 RTL视图 技术映射视图 软件&#xff1a;Quartus II 13.0 (64…

【打工日常】使用docker部署StackEdit编辑器-Markdown之利器

一、StackEdit介绍 StackEdit一款强大的在线Markdown编辑器&#xff0c;不仅具备卓越的写作功能&#xff0c;还支持实时预览、多设备同步等特性。 很多时候基于安全和信息保密的关系&#xff0c;建议放在自己的服务器或者本地linux去运行&#xff0c;这样会比较省心。 二、本次…

使用k-近邻算法改进约会网站的配对效果(kNN)

目录 谷歌笔记本&#xff08;可选&#xff09; 准备数据&#xff1a;从文本文件中解析数据 编写算法&#xff1a;编写kNN算法 分析数据&#xff1a;使用Matplotlib创建散点图 准备数据&#xff1a;归一化数值 测试算法&#xff1a;作为完整程序验证分类器 使用算法&…

MybatisPlus基础入门以及入门案例

目录 一、MyBatisPlus简介 二、MyBatisPlus特性 三、MyBatisPlus支持的数据库 四、框架结构 五、入门案例 1.开发环境 2.创建数据库及表 3.创建Spring Boot工程 4.导入依赖 5.项目结构 6.配置application.yml 7.配置SpringBoot启动类 8.添加实体类 9.添加mapper接口 10.测试…

vue后台管理添加水印简单方式watermark-package

详情参考:https://www.npmjs.com/package/watermark-package 示例方法 <el-button type"primary" click"AddWatermark">添加水印</el-button><el-button type"primary" click"RemoveWatermark">清除水印</el-but…

MKdocs添加顶部公告栏

效果如图&#xff1a; docs/overrides下新建main.html &#xff0c;针对main.html文件 树状结构如下: $ tree -a . ├── .github │ ├── .DS_Store │ └── workflows │ └── PublishMySite.yml ├── docs │ └── index.md │ └──overrides │…

领域驱动设计在互联网业务开发中的实践

至少30年以前&#xff0c;一些软件设计人员就已经意识到领域建模和设计的重要性&#xff0c;并形成一种思潮&#xff0c;Eric Evans将其定义为领域驱动设计&#xff08;Domain-Driven Design&#xff0c;简称DDD&#xff09;。在互联网开发“小步快跑&#xff0c;迭代试错”的大…

数字孪生城市及其他应用场景应用

数字孪生的“虚拟副本”让城市治理不再盲人摸象。 从城市治理的角度来看&#xff0c;数字孪生城市相当于真实世界的“操作系统”&#xff0c;有了它就可以远程对城市的每一个角落进行监测、智慧调度&#xff0c;无论是街道、社区&#xff0c;还是商场、变电站乃至城市排水系统…

使用 JMeter 生成测试数据对 MySQL 进行压力测试

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

【C语言基础教程】getline函数与临时文件

文章目录 前言一、getline函数1.1 为什么需要这个函数1.2 getline函数的使用1.3 使用示例 二、临时文件2.1 临时文件的使用2.2 示例代码 总结 前言 在C语言编程中&#xff0c;处理文本文件是一个常见的任务。然而&#xff0c;有时候我们需要处理那些我们不想在磁盘上创建的临时…

Qwen-VL本地化部署及微调实践

Qwen-VL本地化部署及微调实践 创建虚拟环境模型部署下载模型文件下载项目代码安装python依赖环境修改web_demo_mm.py及openai_api.py的部分代码启动测试 模型微调环境部署数据准备微调 问题 创建虚拟环境 conda create -name vl python3.10.8模型部署 下载模型文件 https://…

React学习——快速上手

文章目录 初步模块思维 初步 https://php.cn/faq/400956.html 1、可以手动使用npm来安装各种插件&#xff0c;来从头到尾自己搭建环境。 如&#xff1a; npm install react react-dom --save npm install babel babel-loader babel-core babel-preset-es2015 babel-preset-rea…

从MATLAB到MWORKS,科学计算与系统建模仿真平台的中国选项

“中国需要自主的科学计算与系统建模仿真平台。” 工业软件是所有复杂系统研发设计、仿真验证和数字制造的必备工具&#xff0c;已经成为衡量一个国家工业竞争力的核心指标。在传统工业软件领域&#xff0c;我们一直处于落后状态&#xff0c;尤其是研发设计类工业软件&#xff…

uniapp开发微信小程序跳转到另一个小程序中

注意&#xff1a;一开始我的云上务工模块是单独的tabbar界面&#xff0c;但是小程序跳转好像不能直接点击tabbar进行&#xff0c;所以我将这里改成了点击首页中的按钮进行跳转 点击这里进行小程序跳转 目录 基础讲解 uniapp小程序跳转的两个方法 调用说明&#xff08;半屏跳转…