【Flutter】Dart:异步

在现代应用开发中,异步编程是不可或缺的部分,尤其是在开发用户界面、网络请求、文件操作等涉及长时间执行的操作时,异步能避免阻塞主线程,从而提升应用的响应速度和用户体验。在 Dart 中,异步编程主要依靠 FutureStream,此外,Dart 还支持 生成器函数 来简化某些异步操作的实现。

本教程将深入介绍 Dart 中的异步编程,涵盖 FutureStream 以及生成器函数的使用。

异步编程概述

在 Dart 中,异步编程的主要目标是避免阻塞主线程(UI 线程),让长时间运行的任务在后台执行,同时主线程可以继续响应用户操作。异步编程通过 FutureStream 来实现。

  • Future:表示一个可能在将来某个时间完成的异步操作,可以成功返回一个结果或抛出错误。
  • Stream:类似于 Future,但可以在一段时间内多次返回数据。
  • 生成器函数:一种简化异步数据生成的机制,通常与 async*yield 关键字结合使用。

Future详解

Future 是 Dart 异步编程的基础,它表示一个将在未来完成的计算。Future 有两种状态:未完成(pending)完成(completed)。当一个异步操作完成时,Future 要么返回结果(成功),要么抛出异常(失败)。

创建 Future

Future 可以通过多种方式创建,包括 Future.value()Future.error() 和异步函数 async 的返回值。

示例:使用 Future.value()

void main() {Future<String> future = Future.value('Hello, Dart Future!');future.then((value) => print(value));
}

示例:使用异步函数

Future<String> fetchData() async {// 模拟网络请求,延迟 2 秒返回结果await Future.delayed(Duration(seconds: 2));return 'Data fetched!';
}void main() async {print('Fetching data...');String data = await fetchData();print(data);
}

在上面的示例中,fetchData 是一个异步函数,返回一个 Future<String>,并通过 await 关键字等待 Future 完成。在调用该函数时,主线程不会被阻塞。

thencatchError 处理结果

使用 Future 时,结果通常通过 then() 方法处理,错误通过 catchError() 处理。then() 方法会在 Future 完成后执行回调。

示例:处理结果和错误

void main() {Future<int> future = Future(() {return 42;});future.then((value) {print('Future completed with value: $value');}).catchError((error) {print('An error occurred: $error');});
}

asyncawait

在 Dart 中,asyncawait 提供了一种简洁的语法来处理异步操作,使代码看起来更像同步代码。

示例:使用 asyncawait

Future<int> fetchNumber() async {await Future.delayed(Duration(seconds: 1));  // 模拟耗时操作return 100;
}void main() async {print('Start fetching number...');int number = await fetchNumber();print('Fetched number: $number');
}

通过 async 标记一个函数为异步,使用 await 等待 Future 完成。在上面的例子中,fetchNumber() 返回一个 Future<int>,主线程等待该 Future 完成后继续执行。

Stream详解

Future 不同,Stream 代表一个异步数据的序列,可以多次发出数据。在 Dart 中,Stream 是处理大量异步事件(如用户输入、文件操作、网络请求)的重要工具。

创建 Stream

Stream 主要有两种类型:单订阅流(single-subscription stream)广播流(broadcast stream)

  • 单订阅流:只能有一个监听器。
  • 广播流:可以有多个监听器,通常用于事件广播。

示例:单订阅流

void main() {Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]);stream.listen((value) {print('Stream value: $value');});
}

示例:广播流

void main() {Stream<int> stream = Stream<int>.periodic(Duration(seconds: 1), (count) => count).asBroadcastStream();stream.listen((value) {print('Listener 1: $value');});stream.listen((value) {print('Listener 2: $value');});
}

在广播流中,多个监听器可以同时监听同一个 Stream,在上面的例子中,两个监听器同时监听并处理同一个 Stream

监听 Stream

通过 listen() 方法可以订阅 Stream,并处理流中的数据。

示例:处理 Stream

Stream<int> countStream(int max) async* {for (int i = 1; i <= max; i++) {yield i;await Future.delayed(Duration(seconds: 1));  // 模拟延迟}
}void main() async {Stream<int> stream = countStream(5);await for (int value in stream) {print('Stream value: $value');}
}

在这个例子中,countStream() 是一个生成器函数,通过 yield 发出数据,并通过 await for 逐个读取 Stream 中的数据。

转换 Stream

Stream 提供了许多方法用于转换流中的数据,比如 map()where()reduce() 等。

示例:转换 Stream

void main() {Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]);stream.map((value) => value * 2).where((value) => value > 5).listen((value) {print('Transformed Stream value: $value');});
}

这个例子展示了如何使用 map()where() 对流中的数据进行转换和过滤。

生成器函数

生成器函数可以生成一系列异步数据,它们使用 async*yield 关键字。生成器函数返回一个 Stream,可以逐步生成多个数据项。

sync*async*

  • sync*:同步生成器,用于生成一系列同步数据。
  • async*:异步生成器,用于生成一系列异步数据。

示例:使用 sync*

Iterable<int> syncGenerator(int max) sync* {for (int i = 1; i <= max; i++) {yield i;}
}void main() {var generator = syncGenerator(5);for (var value in generator) {print('Generated value: $value');}
}

示例:使用 async*

Stream<int> asyncGenerator(int max) async* {for (int i = 1; i <= max; i++) {yield i;await Future.delayed(Duration(seconds: 1));}
}void main() async {await for (var value in asyncGenerator(5)) {print('Generated async value: $value');}
}

async* 生成器与 sync* 不同的是,它会返回 Stream,并且可以处理异步任务。上面的例子中,asyncGenerator() 生成异步数据,并通过 await for 逐步读取。

总结

Dart 中的异步编程通过 FutureStream 和生成器函数为开发者提供了强大的工具,帮助处理复杂的异步操作。Future 用于处理一次性的异步任务,Stream 适合处理一系列异步事件,而生成器函数则提供了简洁的异步数据生成机制。

通过合理使用异步编程模式,开发者可以编写出高效、响应迅速的 Flutter 应用。在实际开发中,掌握这些异步工具对于提升应用性能和用户体验至关重要。

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

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

相关文章

【单元测试】深入解剖单元测试的思维逻辑

目录 一、前言二、准备环境三、 常用的mock语句3.1 模拟指定类的对象实例&#xff0c;用于模拟依赖对象&#xff08;类成员&#xff09;3.2 定义被测试对象3.3 模拟枚举类型/静态方法3.4 模拟依赖方法3.5 模拟构造方法3.6 验证方法调用次数3.7 验证返回值3.8 验证异常对象 四、…

第十六周:机器学习笔记

第十六周周报 摘要Abstratc一、机器学习1. Pointer Network&#xff08;指针网络&#xff09;2. 生成式对抗网络&#xff08;Generative Adversarial Networks | GAN&#xff09;——&#xff08;上&#xff09;2.1 Generator&#xff08;生成器&#xff09;2.2 Discriminator&…

ssm企业库存管理微信小程序-计算机毕业设计源码82704

摘 要 本文基于SSM框架&#xff0c;设计与实现了一个企业库存管理微信小程序。该小程序主要包括用户登录、库存查询、入库操作、出库操作等功能模块。在设计过程中&#xff0c;采用了前后端分离的架构&#xff0c;前端使用了微信小程序原生开发工具进行开发&#xff0c;后端使用…

【C++篇】探索STL之美:熟悉使用String类

CSDN 文章目录 前言 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&…

ApacheShiro反序列化 550 721漏洞

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理个漏洞被称为 Shiro550 是因为在Apache Shiro的GitHub问题跟踪器中&#xff0c;该漏洞最初被标记为第550个问题,721漏洞名称也是由此而来 Shiro-550 CVE-2016-4437 Shiro反序列化Docker复现 …

Android GPU Inspector分析帧数据快速入门

使用 谷歌官方工具Android GPU Inspector (AGI) 可以对Android 应用进行深入和全面的系统性能分析和帧性能分析 。AGI 是一个非常强大的分析工具&#xff0c;尤其是在需要诊断 GPU 性能问题和优化应用时&#xff0c;可以帮助你精准找到性能瓶颈。本文介绍如何使用该工具对帧数据…

HTTP Proxy环境下部署Microsoft Entra Connect和Health Agents

在企业环境中&#xff0c;时常需要通过使用HTTP Proxy访问Internet&#xff0c;在使用HTTP Proxy访问Internet的环境中部署Microsoft Entra Connect和Microsoft Entra Connect Health Agents可能会遇到一些额外的配置步骤&#xff0c;以便这些服务能够正常连接到Internet。 一…

Windows系统PyCharm右键运行.sh文件

在参考了Windows系统下pycharm运行.sh文件&#xff0c;执行shell命令_shell在pycharm-CSDN博客 和深度学习&#xff1a;PyCharm中运行Bash脚本_pycharm bash-CSDN博客 配置了右键执行.sh文件之后&#xff0c;发现在Windows的PyCharm中直接右键运行sh文件&#xff0c;存在如下…

【MyBatis】MyBatis-config标签详解

目录 MyBatis配置文件标签详解configuration标签properties标签typeAliases标签environments标签environment标签transactionManager标签dataSource标签mappers标签 MyBatis配置文件标签详解 我们在使用MyBatis框架的时候需要一个配置文件——MyBatis-config.xml来告诉MyBatis…

Android按钮Button

Button是程序用于和用户进行交互的一个重要控件。Button也是继承自TextView&#xff0c;既可以显示文本&#xff0c;又可以显示图片&#xff0c;二者在UI上的区别主要是 Button 控件有个按钮外观&#xff0c;提示用户单击。 图1 Button示意图 Button最主要的功能是通过单击来执…

K折交叉验证代码实现——详细注释版

正常方法 #---------------------------------Torch Modules -------------------------------------------------------- from __future__ import print_function import numpy as np import pandas as pd import torch.nn as nn import math import torch.nn.functional as …

基于潜空间搜索的策略自适应组合优化(NeurIPS2023)(未完)

文章目录 Abstract1 Introduction2 Related work3 Methods3.1 预备知识3.2 COMPASS4 Experiments4.1 TSP、CVRP和JSSP的标准基准测试4.2 对泛化的鲁棒性:解决变异实例4.3 搜索策略分析5 ConclusionAbstract 组合优化是许多现实应用的基础,但设计高效算法以解决这些复杂的、通…

MongoDB Shell 基本命令(三)生成学生脚本信息和简单查询

一、生成学生信息脚本 利用该脚本可以生成任意个学生信息&#xff0c;包括学号、姓名、班级、年级、专业、课程名称、课程成绩等信息&#xff0c;此处生成2万名学生&#xff0c;学生所有信息都是给定范围后随机生成。 生成学生信息后&#xff0c;再来对学生信息进行简单查询。…

关于武汉芯景科技有限公司的限流开关芯片XJ6241开发指南(兼容LTC4411)

一、芯片引脚介绍 1.芯片引脚 二、系统结构图 三、功能描述 1.CTL引脚控制VIN和VOUT的通断 2.CTL引脚控制STAT引脚的状态 3.输出电压高于输入电压加上–VRTO的值&#xff0c;芯片处于关断状态

Artistic Oil Paint 艺术油画着色器插件

只需轻轻一点&#xff0c;即可将您的视频游戏转化为艺术品&#xff01;&#xff08;也许更多…&#xff09;。 ✓ 整个商店中最可配置的选项。 ✓ 六种先进算法。 ✓ 细节增强算法。 ✓ 完整的源代码&#xff08;脚本和着色器&#xff09;。 ✓ 包含在“艺术包”中。 &#x1f…

【数组知识的扩展①】

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” ArrayList在Java数组中的使用技巧 这篇博客灵感来源于某一天Aileen(&#x1f92b;)遇到了一道数组合并的题&…

python 文件防感染扫描

一、安装 首先&#xff0c;你需要安装 secplugs-python-client 库。你可以通过 pip 命令来安装&#xff1a; pip install secplugs-python-client确保你的 Python 环境已经正确设置&#xff0c;并且网络连接畅通&#xff0c;以便能够顺利安装。 二、基本用法 1. 初始化客户…

【记录】Windows|Windows 修改字体大全(Windows 桌面、VSCode、浏览器)

【记录】Windows&#xff5c;Windows 修改字体大全&#xff08;Windows 桌面、VSCode、浏览器&#xff09; 前言 最近从学长那里发现了一款非常美观的衡水体字体——Maple Mono SC NF。您可以通过以下链接下载该字体&#xff1a;https://github.com/subframe7536/maple-font/…

TiDB替换Starrocks:业务综合宽表迁移的性能评估与降本增效决策

作者&#xff1a; 我是人间不清醒 原文来源&#xff1a; https://tidb.net/blog/6638f594 1、 场景 业务综合宽表是报表生成、大屏幕展示和数据计算处理的核心数据结构。目前&#xff0c;这些宽表存储在Starrocks系统中&#xff0c;但该系统存在显著的性能瓶颈。例如&#…

Vue组件开发的属性

组件开发的属性&#xff1a; 1.ref属性&#xff1a; 如果在vue里&#xff0c;想要获取DOM对象&#xff0c;并且不想使用JS的原生语法&#xff0c;那么就可以使用ref属性 ref属性的用法&#xff1a; 1&#xff09;在HTML元素的开始标记中&#xff0c;或者在Vue子组件中的开始…