Flutter进阶-Future、FutureBuilder、StreamBuilder详解

news2024/11/23 12:36:19

一、时间循环 Event Loop机制

程序之所以卡说白了就是没有时间更新UI界面刷新屏幕导致

常见的卡顿主要是两种:

1.很大的计算量CPU忙不过来

2.等待,等服务器的响应、等用户的输入、等文件的读取...等等

在多线程的机制里每当遇到需要等的东西就开启一个新的线程去守着,负责更新UI的主线程就不会挂起就不会感到卡顿。

但是在Dart中,每个线程都是被封装在Isolate中,每个Isolate是被孤立的隔离开的,彼此不共享内存,彼此间通过发消息来进行通讯

直接运行MicrotaskEvent

Future.sync()

scheduleMicrotask()

Future()

Future.value()

Future.microtask()

Future.delayed()

_.then()_completed.then()

二、FutureBuilder 

通过监听传递的future值的变化进行刷新界面(而不需要使用setState)

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(''),
      ),
      body: FutureBuilder(
        initialData: "haha",
          future:
              Future.delayed(const Duration(seconds: 2), () => throw ('error')),
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return const Icon(Icons.error);
            }
            if (snapshot.hasData) {
              return Text("${snapshot.data}");
            }
            return const CircularProgressIndicator();
          }),
    );
  }

三、Stream与StreamBuilder

future只会打印一次,而Stream会持续不断的执行打印

 final future = Future.delayed(const Duration(seconds: 2), () => 40);
 final stream = Stream.periodic(const Duration(seconds: 1), (_) => 42);


 void test() {
    future.then((value) => print('future completed: $value'));
    stream.listen((event) {
      print("stream: $event");
    });
  }

 @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text(''),
        ),
        body: StreamBuilder(
            stream: stream,
            builder: (context, snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.none:
                  return const Text("none: 没有数据");
                case ConnectionState.waiting:
                  return const Text("waiting: 等待数据流");
                case ConnectionState.active:
                  if (snapshot.hasError) {
                    return Text("active: 错误${snapshot.error}");
                  } else {
                    return Text("active: 正常${snapshot.data}");
                  }
                case ConnectionState.done:
                  return const Text("active: 数据流已经关闭");
              }
            }));
  }

StreamController更加方便的管理stream 

final StreamController streamController = StreamController();
  
@override
  void dispose() {
    streamController.close();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    streamController.sink.add(72);
    streamController.stream.listen((event) {});
  }

  final StreamController streamController = StreamController();
  int count = 10;

  DefaultTextStyle(
                style: Theme.of(context).textTheme.headline4!,
                child: Column(children: [
                  RaisedButton(
                      child: const Text('10'),
                      onPressed: () {
                        count += 10;
                        streamController.sink.add(count);
                      }),
                  StreamBuilder(
                      stream: streamController.stream,
                      builder: (context, snapshot) {
                        switch (snapshot.connectionState) {
                          case ConnectionState.none:
                            return const Text("none: 没有数据");
                          case ConnectionState.waiting:
                            return const Text("waiting: 等待数据流");
                          case ConnectionState.active:
                            if (snapshot.hasError) {
                              return Text("active: 错误${snapshot.error}");
                            } else {
                              return Text("active: 正常${snapshot.data}");
                            }
                          case ConnectionState.done:
                            return const Text("active: 数据流已经关闭");
                        }
                      })
                ]));

 如果被多次监听会报错streamController.stream.listen((event) {});,确实需要可以使用final StreamController streamController = StreamController.broadcast();变成广播

实例:

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _controller = StreamController();
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: StreamBuilder(
            stream: _controller.stream,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Text("你输入了: ${snapshot.data.toString()}",
                    style: const TextStyle(
                        fontSize: 24, fontWeight: FontWeight.bold));
              }
              return const Text("等待...");
            }),
      ),
      body: Stack(children: [
        Puzzle(inputStream: _controller.stream),
        Align(
            alignment: Alignment.bottomCenter,
            child: KeyPad(controller: _controller))
      ]
      ),
    );
  }
}

class KeyPad extends StatelessWidget {
  final StreamController controller;
  const KeyPad({Key? key, required this.controller}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GridView.count(
        shrinkWrap: true,
        childAspectRatio: 2 / 1,
        crossAxisCount: 3,
        mainAxisSpacing: 10,
        crossAxisSpacing: 10,
        children: List.generate(
            9,
            (index) => FlatButton(
                shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(10)),
                color: Colors.primaries[index][200],
                onPressed: () {
                  controller.add(index + 1);
                },
                child: Text(
                  "${index + 1}",
                  style: const TextStyle(fontSize: 24),
                ))));
  }
}

class Puzzle extends StatefulWidget {
  final Stream inputStream;
  const Puzzle({Key? key, required this.inputStream}) : super(key: key);

  @override
  State<Puzzle> createState() => _PuzzleState();
}

class _PuzzleState extends State<Puzzle> with SingleTickerProviderStateMixin {
  late int a, b;
  late Color color;

  late AnimationController _controller; //显示动画

  reset() {
    a = Random().nextInt(5) + 1;
    b = Random().nextInt(5);
    color = Colors.primaries[Random().nextInt(Colors.primaries.length)];
  }

  @override
  void initState() {
    reset();
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 10))
          ..forward();
    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        reset();
        _controller.forward(from: 0.0);
      }
    });
    widget.inputStream.listen((input) {
      if (input == a + b) {
        _controller.forward(from: 0.0);
      }
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
        animation: _controller,
        builder: (context, _) {
          return Positioned(
            top: 400 * _controller.value,
            left: 200 * _controller.value,
            child: Container(
              decoration: BoxDecoration(
                  color: color,
                  border: Border.all(color: Colors.black),
                  borderRadius: BorderRadius.circular(24)),
              padding: const EdgeInsets.all(5),
              child: Text(
                "$a + $b",
                style: const TextStyle(fontSize: 24),
              ),
            ),
          );
        });
  }
}

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

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

相关文章

管理类联考——逻辑——知识篇——分析推理——二、匹配——haimian

匹配 题型识别 题干一般提供3-5个对象和2~3个维度的信息&#xff0c;并描述某对象及信息间的条件关系&#xff0c;要求将信息进行匹配。要从一个一个条件出发&#xff0c;通过逻辑推理&#xff0c;得出正确答案。 思维导图 解题技巧 注意选项的模式&#xff0c;如果已经将关…

Unity | HDRP高清渲染管线学习笔记:HDRP光照系统(二)

目录 一、光源类型和模式 1. Light组件 1.1 General&#xff08;通用设置&#xff09; 1.1.1 LightLayer&#xff08;光照层&#xff09; 1.2 Emission&#xff08;发光设置&#xff09; 1.3 Shadows&#xff08;阴影&#xff09; 二、Light Layer&#xff08;光源分层&…

【C/C++实战项目】扫雷游戏

目录 项目分析 外部头文件 初始化 打印 扫雷游戏函数 main函数 项目分析 游戏需要自定义地图的大小、埋雷的数量通过输入坐标进行扫雷&#xff0c;输入的坐标是埋雷的地方&#xff0c;则游戏失败输入的坐标未埋雷&#xff0c;则该坐标显示周围8个坐标总共的雷数游戏初始…

Ant Design Vue实现表格双击编辑、添加新行、文字提示

早上刚上班&#xff0c;产品就朝我工位走了过来&#xff0c;一看大事不好&#xff0c;肯定又是来提需求的&#xff01; 产品&#xff1a;做一个表格&#xff0c;要实现双击编辑的功能 我&#xff1a;做不了 产品&#xff1a;老板提的 我&#xff1a;好的&#xff0c;可以做 老板…

什么是测试开发工程师?

目录 前言&#xff1a; SDET是做啥的&#xff1f; 为什么需要测试开发&#xff1f; SDET的角色和职责 技术和软技能 非技术能力&#xff1a; 沟通能力 时间管理和组织能力 良好的工作态度 热情 日常工作 事业进阶 总结 前言&#xff1a; 测试开发工程师 (Software …

AIDL中 Binder 的具体流转过程(源码讲解)

前言 本篇文章承接上篇 Binder对象的流转&#xff08;系统服务的调用过程、AIDL的使用过程&#xff09; 上一篇简单笼统地说明了流转的大致方向与手段&#xff0c;此篇文章我们将深入代码层面&#xff0c;看看 Binder 到底是怎么实现的。 一、一个简单的AIDL示例 客户端&…

网关全局过滤器:Java中的强大工具

文章目录 网关过滤器简介网关过滤器的作用过滤器的生命周期实际应用示例权限过滤器解析 总结 网关过滤器简介 网关过滤器是一个位于应用程序和底层服务之间的组件&#xff0c;它截取进出网络请求&#xff0c;并提供对请求和响应进行处理的机制。它可以在请求到达目标服务之前或…

测试老鸟的职业生涯,从初识到功能再到自动化测试,他都经历了啥...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 张工&#xff1a;…

Qt/C++编写onvif工具(搜索/云台/预置位/OSD/录像存储)

一、前言 从最初编写这个工具开始的时间算起来&#xff0c;至少5年多&#xff0c;一直持续完善到今天&#xff0c;这个工具看起来小也不小大也不大&#xff0c;但是也是经历过无数个现场的洗礼&#xff0c;毫不夸张的说&#xff0c;市面上能够遇到的主流的厂商的设备&#xff…

深入探究 ReentrantLock 的应用和原理

博主介绍&#xff1a; ✌博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家✌ Java知识图谱点击链接&#xff1a;体系化学习Java&#xff08;Java面试专题&#xff09; &#x1f495;&#x1f495; 感兴趣的同学可以收…

微信开发者工具-导入小程序项目会自动切换到小游戏打开出错的解决方案

微信开发者工具导入小程序项目会自动切换到小游戏打开出错&#xff0c; 提示Error 提示appid错误&#xff0c;如下图 错误 Error: INVALID_TOKEN...表示网络已断开&#xff0c; 检查开发工具是否连接到网络&#xff0c; 或注销重新登录开发工具试试 提示缺少文件 如果提示缺…

智能安全用电技术电气火灾监控的应用介绍 安科瑞 许敏

摘要&#xff1a;智能安全用电技术在智慧监狱的应用&#xff0c;可以提升监狱智能化管控水平和降低能耗。文章以智能安全用电技术为入手点&#xff0c;简要分析了监狱用电现状&#xff0c;论述了智能安全用电技术在智慧监狱中的具体应用&#xff0c;对智能安全用电技术在智慧监…

【面试题12】HTTP协议三次握手和四次挥手分别是什么

文章目录 一、概览二、三次握手2.1 第一步&#xff1a;客户端向服务端发送 SYN&#xff08;同步&#xff09;包2.2 第二步&#xff1a;服务端返回 ACK&#xff08;确认&#xff09;包和 SYN 包2.3 第三步&#xff1a;客户端返回 ACK&#xff08;确认&#xff09;包 三、四次挥手…

今日分享:音频格式转换软件

小林最近特别喜欢唱歌&#xff0c;不过总是遇到一些麻烦&#xff0c;例如自己录制的音频格式无法在其他设备上播放&#xff0c;或者想把某个歌曲转成适合自己播放的格式。这时候就需要一个好用的音频格式转换器啦&#xff01;小林找了一圈&#xff0c;终于找到了几款可爱又好用…

大数据应用——工程实践III

任务一&#xff1a;完成Hadoop集群部署前环境的准备工作 1.1 虚拟机环境准备 1. 安装虚拟机 2. 克隆虚拟机 3. 修改网络配置 4. 修改主机名和映射 5. 关闭防火墙 1.2 安装JDK 1.3 安装Hadoop 1.4 集群配置 1. 编写集群分发脚本xsync 2. 集群部署规划 表 1.1 hadoop101 …

一份老网工珍藏多年的网络配置笔记

我的网工朋友大家好 俗话说得好&#xff0c;好记性不如烂笔头。 学生时代&#xff0c;我们考试前最喜欢看的就是学霸笔记&#xff0c;但工作之后&#xff0c;却没有人会愿意借给你他们的珍藏笔记了。 今天&#xff0c;想给你分享一个老网工分享在网上的精选笔记&#xff0c;…

java 8 新特性讲解Optional类--Fork/Join 框架--新时间日期API--以及接口的新特性和注解

Optional类 到目前为止&#xff0c;臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前&#xff0c;为了解决空指针异常&#xff0c;Google公司著名的Guava项目引入了Optional类&#xff0c;Guava通过使用检查空值的方式来防止代码污染&#xff0c;它鼓励程序员写…

六、Docker容器数据卷

学习参考&#xff1a;尚硅谷Docker实战教程、Docker官网、其他优秀博客(参考过的在文章最后列出) 目录 前言一、容器数据卷1.1 容器数据卷1.2 怎么用1.3 能干什么 二、实践案例2.1 启动ubuntu容器实例&#xff0c;挂载目录&#xff1a;2.2 在ubuntu容器实例的/tmp/docker_data中…

Android 组件化架构思路

作者&#xff1a;往事一块六毛八 为什么要模块化/组件化 随着APP版本不断的迭代&#xff0c;新功能的不断增加&#xff0c;业务也会变的越来越复杂&#xff0c;APP业务模块的数量有可能还会继续增加&#xff0c;而且每个模块的代码也变的越来越多&#xff0c;这样发展下去单一…

GNS3报错“unable to open TAP device tap0 (No such file or directory)”解决

系统&#xff1a;MacOS 13.4 GNS3版本&#xff1a;2.2.35.1 Tunnelblick&#xff1a;3.8.8b 起因 在gns3中使用cloud节点创建 tap 接口连接路由器报错&#xff1a; 解决办法 借助 Tunnelblick工具创建 Tap 虚拟网卡。Tunnelblick下载地址&#xff1a; https://tunnelblic…