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界面,还需要了解和掌握各个控件的应用。 一个界面的设计,先从创建容器开始,再向…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...
Python爬虫(52)Scrapy-Redis分布式爬虫架构实战:IP代理池深度集成与跨地域数据采集
目录 一、引言:当爬虫遭遇"地域封锁"二、背景解析:分布式爬虫的两大技术挑战1. 传统Scrapy架构的局限性2. 地域限制的三种典型表现 三、架构设计:Scrapy-Redis 代理池的协同机制1. 分布式架构拓扑图2. 核心组件协同流程 四、技术实…...
使用python进行图像处理—图像变换(6)
图像变换是指改变图像的几何形状或空间位置的操作。常见的几何变换包括平移、旋转、缩放、剪切(shear)以及更复杂的仿射变换和透视变换。这些变换在图像配准、图像校正、创建特效等场景中非常有用。 6.1仿射变换(Affine Transformation) 仿射变换是一种…...
