目录
一、Future:处理单次异步操作
1. 概念解读
2. 使用场景
3. 基本用法
3.1 创建 Future
3.2 使用 then 消费 Future
3.3 特性
二、Stream:处理连续异步事件流
1. 概念解读
2. 使用场景
3. 基本用法
3.1 创建 Stream
3.2 监听 Stream
3.3 StreamSubscription 订阅者
3.4 Stream 广播模式
4. 特性
三、Future 与 Stream 对比
四、高级技巧与最佳实践
1. Future 的陷阱
2. Stream 的优化
五、async/await
1. 使用 Future + then() 模式
2. 使用 async + await
3. 回调地狱解决
六、总结
相关推荐
一、Future:处理单次异步操作
在 Dart 库中随处可见 Future 对象,通常异步函数返回的对象就是一个 Future。 当一个 future 执行完后,他里面的值就可以使用了,可以使用 then() 来在 future 完成的时候执行其他代码。Future对象其实就代表了在事件队列中的一个事件的结果。
1. 概念解读
-
定义:
Future
表示一个可能在未来完成的 单次异步操作,并返回一个值或错误(代表了事件结果)。 -
状态:
-
未完成(Uncompleted):操作尚未结束。
-
已完成(Completed):
-
成功(
value
):可等待多个异步结果进行后续操作:wait方法。 -
失败(
error
):对异步编程的异常捕获用try/catch
或.catchError()
捕获异常。
-
-
2. 使用场景
-
网络请求(如
http.get
) -
文件读写
-
延迟任务(如
Future.delayed
) -
单次数据库查询
3. 基本用法
3.1 创建 Future
var dio = Dio();//通过 Dio 库发出HTTP GET请求返回的FutureFuture future= dio.get("https://www.wanandroid.com/banner/json");
3.2 使用 then 消费 Future
void main() {var dio = Dio();//通过 Dio 库发出HTTP GET请求返回的FutureFuture future= dio.get("https://www.wanandroid.com/banner/json");//使用 then 消费 future 返回结果future.then((response){print("返回结果:$response");});
}
3.3 特性
-
链式调用:支持通过
.then()
串联多个异步操作。 -
错误传播:错误会沿着链式调用传递,直到被
catchError
捕获。 -
嵌套地狱:避免过度嵌套
.then()
,优先使用async/await(下面有讲)
。
二、Stream:处理连续异步事件流
Future 表示稍后获得的一个数据,所有异步的操作的返回值都用 Future 来表示。但是 Future 只能表示一次异步获得的数据。而 Stream 表示多次异步获得的数据。比如 IO 处理的时候,每次只会读取一部分数据和一次性读取整个文件的内容相比,Stream 的好处是处理过程中内存占用较小。而 Future 是一次性读取整个文件的内容进来,虽然获得完整内容处理起来比较方便,但是如果文件很大的话就会导致内存占用过大的问题。
1. 概念解读
-
定义:
Stream
表示一个 连续的异步事件序列,可以发射多个值(数据、错误、完成信号)。 -
数据流:类似于“管道”,数据从生产者(如网络、传感器)流向消费者。
2. 使用场景
-
实时聊天消息
-
文件下载进度更新
-
用户输入事件(如搜索框输入)
-
传感器数据(如陀螺仪、GPS)
3. 基本用法
3.1 创建 Stream
//创建 StreamStream<List<int>> stream = File("/Users/scc/Downloads/SCCDemo.apk").openRead();
3.2 监听 Stream
//订阅 Streamstream.listen((List<int> bytes) {print("SccFile----Stream执行"); //执行多次});
listen() 其实就是订阅这个Stream,它会返回一个 StreamSubscription 订阅者。订阅者提供了取消订阅的 cancel() 等方法,
3.3 StreamSubscription 订阅者
//创建 StreamStream<List<int>> stream = File("/Users/scc/Downloads/SCCDemo.apk").openRead();//订阅 StreamStreamSubscription<List<int>> listen = stream.listen((List<int> bytes) {print("SccFile----Stream执行"); //执行多次});listen.onData((_){print("替代listen函数");});listen.onDone((){print("结束");});listen.onError((e,s){print("异常");});//暂停,如果没有继续则会退出程序listen.pause();//继续listen.resume();
3.4 Stream 广播模式
Stream有两种订阅模式:单订阅和多订阅。单订阅就是只能有一个订阅者,上面的使用我们都是单订阅模式,而广播是可以有多个订阅者。通过 Stream.asBroadcastStream() 可以将一个单订阅模式的 Stream 转换成一个多订阅模式的 Stream,isBroadcast 属性可以判断当前 Stream 所处的模式。
Stream<List<int>> stream = File("/Users/scc/Downloads/SCCDemo.apk").openRead();//换成一个多订阅模式的 Streamvar broadcastStream = stream.asBroadcastStream();broadcastStream.listen((List<int> bytes) {print("SccFile----BroadcastStream执行111"); //执行多次});broadcastStream.listen((List<int> bytes) {print("SccFile----BroadcastStream执行222"); //执行多次});print("Stream模式:${broadcastStream.isBroadcast}");
4. 特性
-
多值传递:可发射多个数据、错误或完成信号。
-
冷热流(Cold/Hot Stream):
-
冷流:每次监听时开始生成数据(如上述
countNumbers
)。 -
热流:数据生成与监听无关(如用户点击事件)。
-
-
操作符:支持
map
、where
、debounce
等操作符处理数据流。
三、Future 与 Stream 对比
特性 | Future | Stream |
---|---|---|
数据次数 | 单次结果 | 多次事件 |
适用场景 | 一次性异步操作(如 HTTP 请求) | 连续事件流(如聊天、实时更新) |
状态管理 | 只能完成一次 | 可持续发射数据或错误 |
错误处理 | 通过 catchError 或 try/catch | 通过 onError 或 StreamBuilder |
核心方法 | then() , async/await | listen() , async* , yield |
内存占用 | 较低(单次操作) | 较高(需维护订阅关系) |
四、高级技巧与最佳实践
1. Future 的陷阱
-
嵌套地狱:避免过度嵌套
.then()
,优先使用async/await
。 -
未处理的错误:始终用
try/catch
或.catchError()
捕获异常。 -
不必要的异步:同步任务无需包装为
Future
。
2. Stream 的优化
-
资源释放:调用
subscription.cancel()
防止内存泄漏。 -
防抖与节流:使用
debounce
或throttle
优化高频事件(如搜索输入)。 -
广播流:通过
.asBroadcastStream()
支持多个监听者。
五、async/await
使用
async + await
的代码是异步的,但是看起来很像同步代码。当我们需要获得A的结果,再执行B,时,你需要
then()->then(),合理利用 async + await 能够很好的解决回调地狱的问题。
下面是一个简单的网络请求,不同的实现方式,结果是相同的。
1. 使用 Future + then() 模式
void main() {var dio = Dio();dio.get("https://www.wanandroid.com/banner/json").then((response) {print("返回结果:$response");});
}
2. 使用 async + await
void main() async{var dio = Dio();Response response = await dio.get("https://www.wanandroid.com/banner/json");print("返回结果:$response");
}
3. 回调地狱解决
import 'package:dio/dio.dart';// void main() {
// var dio = Dio();
// dio.get("https://www.wanandroid.com/banner/json").then((response) {
// print("返回结果:$response");
// dio.get("https://www.wanandroid.com/article/list/1/json").then((s) {
// print("返回结果:$s");
// });
// });
// }void main() async{var dio = Dio();Response response = await dio.get("https://www.wanandroid.com/banner/json");Response response2 = await dio.get("https://www.wanandroid.com/article/list/1/json");print("返回结果:$response");print("返回结果:$response2");
}
当然如果你觉得这种方式写着不美观可借助 Future.wait 组合两个任务,在两个任务都完成后,再利用进行后面的操作。
Iterable<Future> futures = [_getBanner(), _getArticlelist()];
await Future.wait(futures);
六、总结
-
Future 是处理 单次异步操作 的基石,适合简单、离散的任务。
-
Stream 是管理 连续事件流 的终极方案,适合实时性要求高的场景。
-
选择依据:
-
需要单个结果? → 使用
Future
。 -
需要持续更新? → 使用
Stream
。
-
掌握二者差异并合理运用,可显著提升 Flutter 应用的响应速度和代码可维护性。在实际开发中,常结合 Future
处理单次请求,用 Stream
管理状态(如 Bloc
库)或实时数据流,以实现高效异步编程。
相关推荐
Flutter Isolate入门指南:轻松实现高效并发编程-CSDN博客文章浏览阅读1k次,点赞30次,收藏30次。在Flutter开发中,面对复杂的业务逻辑和大量的数据处理需求,如何确保应用的流畅性和响应速度成为了开发者们关注的焦点。Flutter Isolate作为一种轻量级的并发执行单元,为我们提供了解决这一问题的有效手段。本文将带你深入了解Flutter Isolate的基本概念、使用场景以及如何在Flutter项目中轻松实现高效并发编程。_flutter isolatehttps://shuaici.blog.csdn.net/article/details/145505453Dart 中的Mixin:提高代码重用性和模块化的利器-CSDN博客文章浏览阅读1k次,点赞22次,收藏19次。本文介绍了Dart中Mixin的概念和使用方法。Mixin是一种代码重用机制,允许开发者将一些功能混入到一个类中,而不必通过继承来实现。文章详细阐述了Mixin的定义、使用以及与继承的冲突处理。通过使用Mixin,开发者可以大大提高代码的可重用性和模块化程度,将共通的功能封装起来,在需要的地方引入,避免了重复编写相同的代码。同时,Mixin还可以将复杂的代码逻辑拆分成更小的、可管理的模块,降低了代码的复杂性,提高了代码的可读性和可维护性。
https://shuaici.blog.csdn.net/article/details/145332099
正在参与 2024 博客之星评选活动,希望大佬们多多支持,谢谢啦:
https://www.csdn.net/blogstar2024/detail/070