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

news2024/9/20 17:28:09

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.coloradmin.cn/o/1464956.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

成功经营社区店的商业模式与案例分析

随着互联网的发展&#xff0c;线上购物已经成为了人们生活中不可或缺的一部分。然而&#xff0c;实体店依然具有不可替代的优势&#xff0c;特别是在社区环境中。 社区店不仅能够为居民提供便利的购物体验&#xff0c;还能为店主带来稳定的收入。 本人在社区开鲜奶吧已经5年时…

每日一题——LeetCode1502.判断是否能形成等差数列

方法一 排序 var canMakeArithmeticProgression function(arr) {arr.sort((a,b)>a-b)let diff arr[1]-arr[0]for(let i1;i<arr.length;i){if(arr[i]-arr[i-1]diff) continueelse return false}return true }; 消耗时间和内存情况&#xff1a; 方法二 数学方法 找出ar…

【算法与数据结构】417、LeetCode太平洋大西洋水流问题

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;题目要求雨水既能流向太平洋也能流向大西洋的网格。雨水流向取决于网格的高度。一个比较直接的方式是对…

web.py架构使用database接口连接mysql

安装mysql sudo apt-get update sudo apt-get install mysql-server sudo apt-get install mysql-client测试mysql systemctl status mysql.service配置mysql //修改密码 sudo mysql -u root -p set password for 用户名localhost password(新密码); //修改root的host属性…

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

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

【Flink集群RPC通讯机制(四)】集群组件(tm、jm与rm)之间的RPC通信

文章目录 1. 集群内部通讯方法概述2. TaskManager向ResourceManager注册RPC服务3. JobMaster向ResourceManager申请Slot计算资源 现在我们已经知道Flink中RPC通信框架的底层设计与实现&#xff0c;接下来通过具体的实例了解集群运行时中组件如何基于RPC通信框架构建相互之间的调…

Windows10和Ubuntu22.04双系统安装

概要&#xff1a; 本篇演示Windows10和Ubuntu22.04双系统的安装&#xff0c;先安装Windows10&#xff0c;再安装Ubuntu22.04。 先安装Ubuntu22.04&#xff0c;后安装Windows10见&#xff1a; Ubuntu22.04和Windows10双系统安装-CSDN博客 一、说明 1、电脑 笔者的电脑品牌…

备战蓝桥杯—— 双指针技巧巧答链表2

对于单链表相关的问题&#xff0c;双指针技巧是一种非常广泛且有效的解决方法。以下是一些常见问题以及使用双指针技巧解决&#xff1a; 合并两个有序链表&#xff1a; 使用两个指针分别指向两个链表的头部&#xff0c;逐一比较节点的值&#xff0c;将较小的节点链接到结果链表…

解决Maven爆红以及解决 Idea 卡在 Resolving问题

关于 Idea 卡在 Resolving&#xff08;前提是Maven的setting.xml中配置好了阿里云和仓库&#xff09; 参考文章https://blog.csdn.net/jiangyu1013/article/details/95042611 解决Maven爆红参考文章https://devpress.csdn.net/beijing/656d993b76f0791b6eca7bb0.html?dp_toke…

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

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

跨城租赁再复用 | 保利经典款展厅珠江之畔云游湘江之滨盛大启幕

2023年5月1日 由优积出品的 长沙保利-梅溪天珺营销中心 唯美亮相&#xff0c;举城共鉴&#xff0c;不负一城期待 盛大开放&#xff01; 优积科技可拆装售楼部 首次服务湖南项目 保利梅溪天珺与君说 &#xff0c;赞51 ▲点击观看展厅开放盛况 长沙保利梅溪天珺售楼处是从佛山…

硬件驱动为什么要有WHQL数字签名?

为了保证驱动程序的安全性&#xff0c;避免用户下载到不利于系统稳定和安全的驱动程序&#xff0c;驱动程序签名被设立出来。最初这一过程由代码签名证书来完成&#xff0c;现在取而代之的则是需要对驱动程序做WHQL认证。本文将详细介绍硬件驱动为什么要有WHQL数字签名的相关内…

如何用GPT高效地处理文本、文献查阅、PPT编辑、编程、绘图和论文写作?

原文链接&#xff1a;如何用GPT高效地处理文本、文献查阅、PPT编辑、编程、绘图和论文写作?https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247594986&idx4&sn970f9ba75998f2dd9fa5707d1611a6cc&chksmfa82320dcdf5bb1bdf58c20686d4eb209770e68253ed90d…

中建七局领导一行莅临优积科技考察交流

7月17日&#xff0c;中建七局二公司副总经理、总工程师张体浪、基础设施分公司副总经理兼城建事业部总经理陈才正、BIM技术中心总经理完颜健飞等一行7人来访优积科技&#xff0c;公司CEO刘其东携团队成员热情接待了来访领导。 会上双方对我司预制快建可循环售楼部、绿色科技展厅…

pclpy 可视化点云(多窗口可视化、单窗口多点云可视化)

pclpy 可视化点云&#xff08;多窗口可视化、单窗口多点云可视化&#xff09; 一、算法原理二、代码三、结果1.多窗口可视化结果2.单窗口多点云可视化 四、相关数据五、问题与解决方案1.问题2.解决 一、算法原理 原理看一下代码写的很仔细的。。目前在同一个窗口最多建立2个窗…

2个wordpress优化SEO主题模板

SEO优化wordpress主题 简洁的SEO优化wordpress主题&#xff0c;效果好不好&#xff0c;结果会告诉你&#xff0c;适合SEO公司使用的主题。 https://www.jianzhanpress.com/?p2804 SEO优化海外WordPress主题 简洁的SEO优化海外服务商WordPress主题&#xff0c;为中国制造202…

1、WEB攻防-通用漏洞SQL注入MYSQL跨库ACCESS偏移

用途&#xff1a;个人学习笔记&#xff0c;欢迎指正&#xff01; 前言&#xff1a; 为了网站和数据库的安全性&#xff0c;MYSQL 内置有 ROOT 最高用户&#xff0c;划分等级&#xff0c;每个用户对应管理一个数据库&#xff0c;这样保证无不关联&#xff0c;从而不会影响到其他…

性能测试工具-locust

简介 Locust是基于python语言的性能测试框架。 Locust支持分布式部署&#xff0c;单实例并发线程数可达1000&#xff0c;界面简约。 locust基于事件。 Locust的缺点 1、无可视化脚本编写功能&#xff0c;需要基于Python语言和locust框架进行脚本编写&#xff0c;纯代码编写…

新版Java面试专题视频教程——多线程篇①

新版Java面试专题视频教程——多线程篇① Java多线程相关面试题 0. 问题汇总0.1 线程的基础知识0.2 线程中并发安全 1.线程的基础知识1.1 线程和进程的区别&#xff1f;1.2 并行和并发有什么区别&#xff1f;1.3 创建线程的四种方式1.4 runnabl…

LeetCode 2583.二叉树中的第 K 大层和:层序遍历 + 排序

【LetMeFly】2583.二叉树中的第 K 大层和&#xff1a;层序遍历 排序 力扣题目链接&#xff1a;https://leetcode.cn/problems/kth-largest-sum-in-a-binary-tree/ 给你一棵二叉树的根节点 root 和一个正整数 k 。 树中的 层和 是指 同一层 上节点值的总和。 返回树中第 k …