Flutter中的异步编程
目录
前言
1. Future 和 async/await
1.Future
1.什么是Future?
2.Flutter的三种状态
1.未完成(Uncompleted)
1.定义
2.处理未完成的Future
2.已完成(Completed with a value)
1.概念
2.处理已完成的Future
3.使用async/await
4.Future的已完成状态的处理
3.已失败(Completed with an error)
1.概念
2.处理失败状态的Future
3.使用 async/await
4.捕获和处理错误的最佳实践
1.始终捕获错误
2.提供用户反馈
3.记录错误
3.创建Future
1.使用Future构造函数
2.使用Future.delayed
3.使用Future.value和Future.error
4.处理Future
1.使用then和catchError
2.使用async/await
3.Future的链式调用
2. Stream
1.Stream的两种类型
2.创建Stream
1.使用StreamController
2.使用异步生成器函数
3.监听Stream
4.使用StreamBuilder
5.Stream的高级用法
1.转换Stream
2.合并Stream
6.总结
3.FutureBuilder和StreamBuilder
1.FutureBuilder
2.StreamBuilder
前言
在Flutter应用程序开发中,异步编程是必不可少的。异步编程使应用程序能够在不阻塞主线程的情况下执行耗时操作,如网络请求、文件读取和数据库访问。本文将介绍Flutter中常用的异步编程方法及其最佳实践。
1. Future 和 async/await
1.Future
1.什么是Future?
在Flutter中,Future是一个用于表示异步操作结果的类。它代表一个在将来某个时刻会完成的计算,类似于其他编程语言中的Promise。Future非常适合处理那些需要一些时间才能完成的操作,例如网络请求、文件读取或其他耗时任务。
2.Flutter的三种状态
1.未完成(Uncompleted)
1.定义
表示异步操作尚未完成。在未完成状态的时候,Future尚未提供结果,也没有抛出错误。
当你调用一个异步函数时,它会返回一个未完成的 Future。该 Future 正在等待函数的异步操作完成或抛出错误。
以下是一个创建和使用Future的示例,展示Future在未完成状态时的行为:
Future<String> fetchData() {// 创建一个延迟两秒后完成的Futurereturn Future.delayed(Duration(seconds: 2), () => 'Data fetched');
}void main() {print('Fetching data...');fetchData().then((result) {print(result);}).catchError((error) {print('Error: $error');});print('Waiting for data...');
}
控制台输入信息如下:
Fetching data...
Waiting for data...
Data fetched
这里可以看到,在调用fetchData之后和Future完成之前,控制台输出了”Waiting for data…”。这表示在这段时间内,Future处于未完成状态。
2.处理未完成的Future
通常,我们使用then方法来处理Future完成时的结果,使用catchError方法来处理Future失败时的错误。
此外,可以使用await关键字在异步函数中等待Future完成:
Future<void> fetchDataAndPrint() async {print('Fetching data...');try {String result = await fetchData();print(result);} catch (error) {print('Error: $error');}print('Data fetching completed.');
}void main() {fetchDataAndPrint();
}
执行这个代码时,控制台的输出如下:
Fetching data...
Data fetched
Data fetching completed.
2.已完成(Completed with a value)
1.概念
已完成状态表示异步操作成功完成,并返回了结果。
2.处理已完成的Future
当Future进入已完成状态时,我们可以使用then方法来处理成功的结果,使用catchError方法来处理失败的错误。另外,可以使用async/await来简化异步代码。
以下是一个创建和使用Future的示例,展示如何处理已完成状态的Future:
Future<String> fetchData() {
// 创建一个延迟两秒后完成的Future
return Future.delayed(Duration(seconds: 2), () => 'Data fetched');
}void main() {
print('Fetching data...');
fetchData().then((result) {
// 当Future完成时,处理结果
print(result);
}).catchError((error) {
// 当Future失败时,处理错误
print('Error: $error');
});print('Waiting for data...');
}
执行这段代码时,控制台的输出如下:
Fetching data...
Waiting for data...
Data fetched
在上面的实例中:
1.fetchData函数返回一个在两秒后完成的Future,并返回字符串"Data fetched"。
2.使用then方法处理Future完成时的结果,输出"Data fetched"。
3.使用catchError方法处理Future失败时的错误(示例中未发生错误)。
3.使用async/await
async/await语法使得处理异步操作更加直观和简洁。以下是同样功能的代码,使用async/await:
Future<void> fetchDataAndPrint() async {
print('Fetching data...');
try {
// 使用await等待Future完成
String result = await fetchData();
print(result);
} catch (error) {
print('Error: $error');
}print('Data fetching completed.');
}void main() {
fetchDataAndPrint();
}
执行这个代码时,控制台的输出如下:
Fetching data...
Data fetched
Data fetching completed.
在这个示例中:
1.使用await关键字等待Future完成,并获取其结果。
2.try块用于捕获可能的错误,并在catch块中处理错误。
4.Future的已完成状态的处理
在Flutter的完成状态中,有失败和成功两种情况。
1.对于成功完成的Future,使用then方法处理完成的Future,或者在async函数中是用await。
2.对于失败完成的Future,使用catchError方法处理失败完成的Future,或者在async函数中使用try/catch。
3.已失败(Completed with an error)
1.概念
Future的失败状态表示该异步操作已经完成,但由于某种原因失败,并抛出了一个错误。
2.处理失败状态的Future
当Future进入失败状态时,可以使用catchError方法来处理失败的错误,或者在async/await语法中使用try/catch块来捕获和处理错误。
以下是一个创建和使用Future的示例,展示如何处理失败状态的Future:
Future<String> fetchData() {
// 创建一个延迟两秒后失败的Future
return Future.delayed(Duration(seconds: 2), () => throw 'Failed to fetch data');
}void main() {
print('Fetching data...');
fetchData().then((result) {
// 当Future成功完成时,处理结果
print(result);
}).catchError((error) {
// 当Future失败时,处理错误
print('Error: $error');
});print('Waiting for data...');
}
执行这段代码时,控制台的输出如下:
Fetching data...
Waiting for data...
Error: Failed to fetch data
在上面这个示例中:
1. fetchData函数返回一个在两秒后失败的Future,并抛出字符串"Failed to fetch data"。
2. 使用then方法处理Future成功完成时的结果(在此示例中不会被调用)。
3. 使用catchError方法处理Future失败时的错误,输出"Error: Failed to fetch data"。
3.使用 async/await
async/await语法使得处理异步操作的失败更加直观和简洁。以下是同样功能的代码,使用async/await:
Future<void> fetchDataAndPrint() async {
print('Fetching data...');
try {
// 使用await等待Future完成
String result = await fetchData();
print(result);
} catch (error) {
// 捕获并处理错误
print('Error: $error');
}print('Data fetching completed.');
}void main() {
fetchDataAndPrint();
}
执行这个代码时,控制台的输出如下:
Fetching data...
Error: Failed to fetch data
Data fetching completed.
在这个示例中:
1. 使用await关键字等待Future完成,并获取其结果。
2. try块用于捕获可能的错误,并在catch块中处理错误。
4.捕获和处理错误的最佳实践
理解和处理Future的失败状态是Flutter异步编程的重要部分。通过使用catchError和try/catch语法,可以有效地捕获和处理异步操作中的错误,从而编写更健壮和稳定的Flutter应用程序。
1.始终捕获错误
无论使用then和catchError还是async/await,始终确保捕获并处理Future中的错误,以避免未处理的异常。
2.提供用户反馈
在用户界面上提供适当的反馈,如显示错误消息或提示用户重试操作。
3.记录错误
在开发和调试过程中,记录错误信息有助于查找和修复问题。
3.创建Future
创建一个Future非常简单,可以使用Future构造函数、Future.delayed、Future.value和Future.error等方法。
1.使用Future构造函数
Future<String> fetchData() {return Future(() {return 'Data fetched';});
}void main() {fetchData().then((data) {print(data);});
}
2.使用Future.delayed
Future<String> fetchData() {return Future.delayed(Duration(seconds: 2), () {return 'Data fetched';});
}void main() {fetchData().then((data) {print(data);});
}
3.使用Future.value和Future.error
void main() {Future.value('Immediate data').then((data) {print(data);});Future.error('An error occurred').catchError((error) {print(error);});
}
4.处理Future
处理Future通常有两种方式:使用then和catchError方法,或者使用async/await语法。
1.使用then和catchError
Future<String> fetchData() {return Future.delayed(Duration(seconds: 2), () {return 'Data fetched';});
}void main() {fetchData().then((data) {print(data);}).catchError((error) {print('Error: $error');});
}
2.使用async/await
Future<String> fetchData() async {await Future.delayed(Duration(seconds: 2));return 'Data fetched';
}void main() async {try {String data = await fetchData();print(data);} catch (error) {print('Error: $error');}
}
3.Future的链式调用
多个Future可以通过链式调用连接在一起,从而依次处理多个异步操作。
Future<void> fetchData() {
return Future.delayed(Duration(seconds: 2), () {
print('Step 1: Data fetched');
}).then((_) {
return Future.delayed(Duration(seconds: 1), () {
print('Step 2: Additional data fetched');
});
}).then((_) {
print('Step 3: All steps completed');
});
}void main() {
fetchData();
}
2. Stream
在Flutter中,Stream用于表示一系列异步数据事件。与Future不同,Stream可以提供多个值而不是单个值。它非常适合处理诸如用户输入、实时数据更新和传感器数据等连续数据流。本文将详细介绍Flutter中`Stream`的基本概念和用法。
1.Stream的两种类型
1.单订阅Stream(Single-subscription Stream):只能被单个监听器(listener)监听。这种Stream适用于大多数情况。
2.广播Stream(Broadcast Stream):可以被多个监听器同时监听。这种Stream适用于需要多个订阅者的情况,如事件总线(Event Bus)。
2.创建Stream
创建Stream有多种方式,常见的包括使用StreamController和异步生成器函数。
1.使用StreamController
StreamController用于创建和管理Stream。
void main() {// 创建一个StreamControllerfinal controller = StreamController<int>();// 获取Streamfinal stream = controller.stream;// 监听Streamstream.listen((data) {print('Data: $data');}, onDone: () {print('Stream closed');});// 添加数据到Streamcontroller.add(1);controller.add(2);controller.add(3);// 关闭Streamcontroller.close();
}
执行这个代码时,控制台的输出如下:
Data: 1
Data: 2
Data: 3
Stream closed
2.使用异步生成器函数
可以使用async*和yield关键字创建Stream。
Stream<int> countStream(int to) async* {for (int i = 1; i <= to; i++) {await Future.delayed(Duration(seconds: 1));yield i;}
}void main() {final stream = countStream(5);stream.listen((data) {print('Data: $data');}, onDone: () {print('Stream closed');});
}
执行这个代码时,控制台的输出如下:
Data: 1
Data: 2
Data: 3
Data: 4
Data: 5
Stream closed
3.监听Stream
使用listen方法可以监听Stream,并处理接收到的数据和错误。
stream.listen((data) {print('Data: $data');},onError: (error) {print('Error: $error');},onDone: () {print('Stream closed');},cancelOnError: false, // 当为true时,接收到错误后将取消订阅
);
4.使用StreamBuilder
在Flutter中,StreamBuilder小部件用于根据Stream构建UI。它会监听Stream并在每次接收到数据时重新构建UI。
Stream<int> countStream(int to) async* {
for (int i = 1; i <= to; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('StreamBuilder Example'),
),
body: Center(
child: StreamBuilder<int>(
stream: countStream(5),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else if (!snapshot.hasData) {
return Text('No Data');
} else {
return Text('Count: ${snapshot.data}');
}
},
),
),
);
}
}void main() => runApp(MaterialApp(home: MyHomePage()));
在这个示例中,StreamBuilder监听countStream,并根据Stream的状态更新UI。
5.Stream的高级用法
1.转换Stream
使用Stream的转换方法可以方便地处理数据,例如使用map方法转换数据:
Stream<int> countStream(int to) async* {for (int i = 1; i <= to; i++) {await Future.delayed(Duration(seconds: 1));yield i;}
}void main() {final stream = countStream(5).map((data) => data * 2);stream.listen((data) {print('Transformed Data: $data');});
}
2.合并Stream
可以使用StreamGroup来合并多个Stream:
void main() {final stream1 = Stream.fromIterable([1, 2, 3]);final stream2 = Stream.fromIterable([4, 5, 6]);final mergedStream = StreamGroup.merge([stream1, stream2]);mergedStream.listen((data) {print('Merged Data: $data');});
}
6.总结
Stream在Flutter中是处理异步数据事件的强大工具。通过理解和使用StreamController、异步生成器函数以及StreamBuilder,可以有效地处理和显示连续的数据流。希望本文能帮助你更好地理解和使用Flutter中的Stream。
Future 表示不会立即完成的计算。普通函数会返回结果,而异步函数则会返回 Future,后者最终会包含结果。Future 会告诉您结果何时准备就绪。
Stream(流)是一系列异步事件。它类似于异步 Iterable — 流不会在您请求时获取下一个事件,而是在事件准备就绪时告诉您有事件发生。
3.FutureBuilder和StreamBuilder
FutureBuilder和StreamBuilder是Flutter中用于处理异步数据的两个常用小部件。
1.FutureBuilder
FutureBuilder用于构建依赖于Future的widget。
FutureBuilder<String>(future: fetchUserOrder(),builder: (context, snapshot) {if (snapshot.connectionState == ConnectionState.waiting) {return CircularProgressIndicator();} else if (snapshot.hasError) {return Text('Error: ${snapshot.error}');} else {return Text('Order: ${snapshot.data}');}},
);
2.StreamBuilder
StreamBuilder用于构建依赖于Stream的widget。
StreamBuilder<int>(stream: countStream(5),builder: (context, snapshot) {if (snapshot.connectionState == ConnectionState.waiting) {return CircularProgressIndicator();} else if (snapshot.hasError) {return Text('Error: ${snapshot.error}');} else if (!snapshot.hasData) {return Text('No Data');} else {return Text('Count: ${snapshot.data}');}},
);
相关文章:

Flutter中的异步编程
目录 前言 1. Future 和 async/await 1.Future 1.什么是Future? 2.Flutter的三种状态 1.未完成(Uncompleted) 1.定义 2.处理未完成的Future 2.已完成(Completed with a value) 1.概念 2.处理已完成的Future 3.使用async/await 4.Fu…...

vue3 路由带传参跳转;刷新后消失。一次性参数使用。
解决vue3 怎么做到路由跳转传参刷新后消失 解决路由跳转传参去除问题 想要跳转后根据参数显示对应的tab,但url传参刷新会持续保留无法重置。 router.replace替换又会导致显示内容为router.replace后的,传参目的丢失。 业务逻辑: 完成对应操作…...

Unity新输入系统结构概览
本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 在学习新输入系统之前,我们需要对其构成有个印象 1.输入动作(Inputaction) 是定义输…...

18104 练习使用多case解题
### 伪代码 1. 读取第1批测试数据的CASE数量。 2. 处理第1批测试数据,计算每个CASE的最小公倍数并输出。 3. 输出“group 1 done”。 4. 处理第2批测试数据,直到遇到两个0,计算每个CASE的最小公倍数并输出。 5. 输出“group 2 done”。 6. 处…...

【AI人工智能】文心智能体 - 你的专属车牌设计师
引言 自AI盛行以来,不断有各种各样的人工智能产品崭露头角。我们逐步跟着不断产生的人工智能来使自己的工作和生活变得更加智能化!那么我们是否能够创造一款专属于自己的人工智能产品呢? 文心智能体平台就给我们提供了这样的机会,…...

Linux-服务器硬件及RAID配置实验
系列文章目录 提示:仅用于个人学习,进行查漏补缺使用。 1.Linux介绍、目录结构、文件基本属性、Shell 2.Linux常用命令 3.Linux文件管理 4.Linux 命令安装(rpm、install) 5.Linux账号管理 6.Linux文件/目录权限管理 7.Linux磁盘管理/文件系统 8.Linu…...

白屏检测系统的设计与实现
目录 一、 什么是白屏问题?二、 问题分析与拆解2.1 人工判定一个白屏问题的逻辑2.2 自动化判定一个白屏问题的算法思想 三、 白屏检测算法3.1 图像灰度化3.2 图像二值化3.3 计算(判定为白屏)置信度 四、 白屏检测系统的设计与实现4.1 UI自动化…...

Real-Time Open-Vocabulary Object Detection:使用Ultralytics框架进行YOLO-World目标检测
Real-Time Open-Vocabulary Object Detection:使用Ultralytics框架进行YOLO-World目标检测 前言相关介绍前提条件实验环境安装环境项目地址LinuxWindows 使用Ultralytics框架进行YOLO-World目标检测进行训练进行预测进行验证 扩展目标跟踪设置提示 参考文献 前言 由…...

区块链用什么编程语言实现?
. 主流区块链的开发语言主要有:C、Go、Java、Rust、C#。 C使用率最高,其次是Go,很少有人用python开发区块链。...

【网络编程】UDP通信基础模型实现
udpSer.c #include<myhead.h> #define SER_IP "192.168.119.143" #define SER_PORT 7777 int main(int argc, const char *argv[]) {//1.创建int sfd socket(AF_INET,SOCK_DGRAM,0);if(sfd -1){perror("socket error");return -1;}//2.连接struct…...

Docker Compose 常用命令详解
Docker Compose 常用命令详解 Docker Compose 是 Docker 官方编排工具之一,用于定义和运行多容器 Docker 应用程序。通过 docker-compose.yml 文件,开发者可以轻松管理服务、网络、卷以及各服务之间的依赖关系。以下将介绍一些常用的 Docker Compose 命…...

超级外链工具,可发9600条优质外链
超级外链工具,是一款在线全自动化发外链的推广工具。使用本工具可免费为网站在线批量增加外链,大大提高外链发布工作效率,是广大草根站长们必备的站长工具。 外链工具只是网站推广的辅助工具,一般适用于短时间内无法建设大量外链…...

VisionPro二次开发学习笔记13-使用CogToolBlock进行图像交互
该程序演示了如何使用CogToolBlock进行图像交互. 从vpp文件中加载一个ToolBlock。 用户可以通过应用程序窗体上的数字增减控件修改ToolBlock输入端子的值。 用户还可以从coins.idb或采集FIFO中选择图像。 “运行一次”按钮执行以下操作: 获取下一个图像或读取下一…...

比特币价格分析:市场重置完成,下一个目标:70,000 美元
比特币再次处于关键支撑位,面临可能影响其短期前景的关键考验。分析师们正密切关注比特币是否重复熟悉的模式,暗示可能出现重大走势。 OKNews分析师Josh表示,比特币一直处于看跌趋势,正如 4 日图上的超级趋势指标所示。这种趋势的…...

大模型笔记5 Extractive QA任务评估
目录 Extractive QA任务评估 Extractive QA评测指标 precision, recall, f1 ROUGE 划分训练与评估数据集 token位置评估 单个token位置评估 输入label的token位置 预测token位置 评估 Wandb 共享机器同时登录 样本类别平衡 标记token label时对窗口进行筛选 训练…...

RCE绕过方式
目录 小于8个字符突破限制 无字母数字执行 php7的做法 php5的思考 PHP5shell 深入理解glob通配符 构造POC,执行任意命令 无参数读文件和RCE总结 代码解读 构造. 另一种构造方法 小于8个字符突破限制 但也只能执行一些非常短的命令,没有什么意义…...

Flutter 电视投屏模块
前言 村里的老人说:“珍爱生命,远离低头族。“ 之前开发的一个 DIM 项目 Tarsier,里面有一个分享视频的功能,同时包含在线视频播放、电视直播等。 考虑到用户在手机上看视频的体验问题,需要增加一个投屏功能,以便用户可以电影、电视直播等投到电视上用大屏幕观看。 用…...

【机器学习】卷积神经网络简介
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 卷积神经网络简介1. 引言2. CNN的基本概念2.1 什么是卷积神经网络2.2 CNN与传统…...

时间函数链接函数等
1. 2.top相当于windows任务管理器 3.命令模式下不加冒号20G直接跳转行数 4. 相当于strcat 5.:13,15y 13行到15行复制 6. Ctrl 右 】是追踪命令 7. vi off_t -t看类型 8. qa关闭所有 9.gg 移动最前面 GG移动到最后面 10.终端中的全选命令1. 使用快捷键&…...

Android控件(示例)
在Android应用程序中,界面由布局和组件组成。布局相当于框架,而控件则是框架里面的内容。了解过Android布局后,如果要设计ui界面,还需要了解和掌握各个控件的应用。 一个界面的设计,先从创建容器开始,再向…...

图论------贝尔曼-福德(Bellman-Ford)算法
算法概述: Bellman-Ford算法核心代码如下 for(int i 1;i<n-1;i) for(int j 1;j<m;j) if(dic[v[j]]> dic[u[j]] w[j]] dic[v[j]] dic[u[j]] w[j]; 首先我们要了解一个点就是我们这次不再使用邻接矩阵来存储图的信息,而是定义三个一维数组来…...

带你彻底搞懂useLayoutEffect的使用场景
开篇第一句: useLayoutEffect 可能会影响性能。尽可能使用 useEffect。 useLayoutEffect 是 useEffect 的一个版本,在浏览器重新绘制屏幕之前触发。 使用方法 useLayoutEffect(setup, dependencies?)调用 useLayoutEffect 在浏览器重新绘制屏幕之前进行布局测量&…...

大厂进阶之二:React高级用法HOC、Hooks对比、异步组件
本文分文三部分: HOC高阶组件 higher order componentHooks 16.8版本后新增的钩子API异步组件使用lazy和suspense两个api实现组件代码打包分割和异步加载 一、HOC高阶组件 1、定义 高阶组件不是组件而是函数,是react中用于复用组件逻辑的高级技巧&am…...

【扒代码】ope.py
文件目录: 引用方式 if not self.zero_shot: # 非零样本情况下,计算边界框的宽度和高度 box_hw torch.zeros(bboxes.size(0), bboxes.size(1), 2).to(bboxes.device) box_hw[:, :, 0] bboxes[:, :, 2] - bboxes[:, :, 0] # 宽度 box_hw[:, :, 1] bbox…...

【Rust光年纪】探索Rust终端编程:从跨平台操作到用户界面设计
构建跨平台终端应用的完美选择:Rust 库综述 前言 随着终端应用程序的发展,越来越多的开发者开始寻找跨平台的、易于使用的库来构建终端用户界面和执行终端操作。本文将介绍几个流行的 Rust 库,它们提供了丰富的功能和灵活的 API 来满足不同…...

67、ceph
一、ceph 1.1、ceph概念 ceph是一个开源的,用c语言写的分布式的存储系统。存储文件数据。 /dev/sdb fdisk /dev/sdb gdisk /dev/sdb lvm 逻辑卷 可以扩容 raid 磁盘阵列 高可用 基于物理意义上的单机的存储系统。 分布式有多台物理磁盘组成一个集群&…...

最大正方形[中等]
优质博文:IT-BLOG-CN 一、题目 在一个由0和1组成的二维矩阵内,找到只包含1的最大正方形,并返回其面积。 示例 1: 输入:matrix [["1","0","1","0","0"],[&quo…...

JavaScript 浅谈观察者模式 前端设计模式
2、观察者模式 2.1、观察者模式 2.1.1、前言 定义一种一对多的依赖关系,当一个对象发生变化时,所有依赖于它的对象都会自动收到通知并更新。 两个角色: Subject(主题/被观察者) Observer(观察者&…...

【自动驾驶】自定义消息格式的话题通信(C++版本)
目录 新建消息文件更改包xml文件中的依赖关系更改cmakelist文件中的配置执行时依赖改变cmakelist编译顺序发布者程序调用者程序新建launch文件程序测试 新建消息文件 在功能包目录下,新建msg文件夹,下面新建mymsg.msg文件,其内容为 string …...

提升前端性能的JavaScript技巧
1. 前端JavaScript性能问题 前端JavaScript的性能问题可以显著影响Web应用的用户体验和整体性能。以下是一些常见的前端JavaScript性能问题: 1.1. 频繁的DOM操作 问题描述:JavaScript经常需要与DOM(文档对象模型)交互来更新页面内容。然而,每次DOM操作都可能触发浏览器的…...