一、Future 和 Stream 是处理异步操作的两个重要概念:
Future:
Future 用于表示一个延迟操作的值或错误,即异步操作的结果。通过 Future,可以在异步操作完成后获取其结果。可以使用 async 和 await 关键字来处理 Future,使得异步操作更加直观和易于管理。
Stream:
Stream 则用于处理一系列异步数据(事件)的序列。它可以持续地产生数据,而不是单一的结果。Stream 可以用于处理事件、文件读写、状态管理等需求。使用 StreamController 可以很好的控制 Stream 的创建和数据添加。
二、Future的使用:
async 和 await。
async:用于在方法或函数声明前添加,表示该方法是一个异步方法。在异步方法中,执行顺序可以是非阻塞的,不会阻塞当前线程。
await:用于在异步方法中等待并获取异步表达式的执行结果,只能在被 async 修饰的方法中使用。
1、模拟一个异步请求数据的实现
通过async关键字声明一个异步方法,延迟2秒后返回模拟的结果String值。
Future<String> getAsyncData() async {
setState(() {
asyncData = "开始请求数据";
});
await Future.delayed(const Duration(seconds: 2));
return "返回:Future get async data.";
}
通过按钮点击触发模拟接口请求,获取到异步数据后更新到页面中。
ElevatedButton(
onPressed: () {
getAsyncData().then((value) {
setState(() {
asyncData = value;
});
});
},
child: const Text("Future get async data.")),
Text(asyncData),
2、模拟两个异步请求并行,待全部接口请求完成后获取数据的实现
通过async关键字声明两个异步方法,分别延迟2秒和延迟3秒后,返回模拟的结果String值。
Future<String> getAsyncData2() async {
setState(() {
asyncTowData = "getAsyncData2开始请求数据";
});
await Future.delayed(const Duration(seconds: 2));
setState(() {
asyncTowData = "getAsyncData2完成请求数据";
});
return "延迟2秒返回";
}
Future<int> getAsyncData3() async {
setState(() {
asyncTowData = "getAsyncData3开始请求数据";
});
await Future.delayed(const Duration(seconds: 3));
setState(() {
asyncTowData = "getAsyncData3完成请求数据";
});
return 3;
}
创建第三个异步方法,将上面的两个异步方法添加到数组里面,并行执行。
// 同时执行两个异步方法并等待它们的结果
Future<List<dynamic>> getTowAsyncData() async {
List<Future<dynamic>> futures = [getAsyncData2(), getAsyncData3()];
List<dynamic> result = await Future.wait(futures);
return result;
}
通过按钮点击触发模拟接口请求,获取到异步数据后更新到页面中。
ElevatedButton(
onPressed: () {
getTowAsyncData().then((value) {
var data1 = value[0] as String;
var data2 = value[1] as int;
setState(() {
asyncTowData = "$data1,延迟$data2秒返回";
});
});
},
child: const Text("Future get tow async data.")),
Text(asyncTowData),
3、FutureBuilder 使用
通过FutureBuilder实现请求数据时展示加载组件,请求成功后显示数据。
Widget _init() {
return FutureBuilder(
future: initAsyncData(),
builder: (context, snapshot) {
// 等待状态显示的widget
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
// 错误时显示的widget
} else if (snapshot.hasError) {
return const Text('Error');
// 加载完成后显示的数据
} else {
return _widget();
}
},
);
}
4、FuturePage完整代码
import 'package:flutter/material.dart';
///create by itz on 2024/8/16 14:55
///desc :
class FuturePage extends StatefulWidget {
const FuturePage({super.key});
@override
State<FuturePage> createState() => _FuturePageState();
}
class _FuturePageState extends State<FuturePage> {
String asyncData = "";
String asyncTowData = "";
bool isInit = false;
Future initAsyncData() async {
await Future.delayed(const Duration(seconds: 2));
isInit = true;
}
Future<String> getAsyncData() async {
setState(() {
asyncData = "开始请求数据";
});
await Future.delayed(const Duration(seconds: 2));
return "返回:Future get async data.";
}
Future<String> getAsyncData2() async {
setState(() {
asyncTowData = "getAsyncData2开始请求数据";
});
await Future.delayed(const Duration(seconds: 2));
setState(() {
asyncTowData = "getAsyncData2完成请求数据";
});
return "延迟2秒返回";
}
Future<int> getAsyncData3() async {
setState(() {
asyncTowData = "getAsyncData3开始请求数据";
});
await Future.delayed(const Duration(seconds: 3));
setState(() {
asyncTowData = "getAsyncData3完成请求数据";
});
return 3;
}
// 同时执行两个异步方法并等待它们的结果
Future<List<dynamic>> getTowAsyncData() async {
List<Future<dynamic>> futures = [getAsyncData2(), getAsyncData3()];
List<dynamic> result = await Future.wait(futures);
return result;
}
@override
Widget build(BuildContext context) {
Widget w = isInit ? _widget() : _init();
return Scaffold(
appBar: AppBar(
title: const Text("Future"),
),
body: w,
);
}
Widget _init() {
return FutureBuilder(
future: initAsyncData(),
builder: (context, snapshot) {
// 等待状态显示的widget
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
// 错误时显示的widget
} else if (snapshot.hasError) {
return const Text('Error');
// 加载完成后显示的数据
} else {
return _widget();
}
},
);
}
Widget _widget() {
return Container(
margin: const EdgeInsets.all(16),
child: ListView(
children: [
ElevatedButton(
onPressed: () {
getAsyncData().then((value) {
setState(() {
asyncData = value;
});
});
},
child: const Text("Future get async data.")),
Text(asyncData),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
getTowAsyncData().then((value) {
var data1 = value[0] as String;
var data2 = value[1] as int;
setState(() {
asyncTowData = "$data1,延迟$data2秒返回";
});
});
},
child: const Text("Future get tow async data.")),
Text(asyncTowData),
],
),
);
}
}
三、Stream的使用
在Flutter中,Stream 是用于处理异步事件序列的概念,常见应用包括:
异步数据获取:Stream在异步数据获取方面非常有用。例如,在网络请求中,可以使用 Stream 来处理异步数据的传输和响应。通过监听 Stream,可以实时获取数据并更新应用程序的界面,实现动态数据展示的功能。
状态管理:Stream在状态管理中扮演着重要的角色。通过创建包含状态信息的 Stream,可以在应用程序中管理状态的变化。当状态发生变化时,通过 Stream 向订阅者(监听者)发送新的状态信息,从而触发相应的操作或界面更新。
事件总线:Stream可以作为事件总线,用于在应用程序中处理和传递事件。通过创建一个全局的 Stream,不同部分的应用程序可以监听并发送事件,实现模块之间的通信和交互。这种方式可以实现解耦和灵活的组件通信。
文件读写:Stream`也可以用于处理文件读写操作。例如,读取大文件时可以使用 Stream实现分块读取,提高读取效率。同样,可以通过 Stream 监听文件写入事件,实现实时监控文件变化等功能。
1、异步数据获取
1)创建StreamController 控制器,控制 Stream 的创建、数据添加 和 关闭等操作。
final StreamController _streamController = StreamController();
2)创建异步方法,模拟异步数据获取
getStreamData() async {
for (int i = 0; i < 10; i++) {
await Future.delayed(const Duration(seconds: 1));
// 发送值
_streamController.sink.add(i);
}
await Future.delayed(const Duration(seconds: 1));
// 发送值
_streamController.sink.add("done");
}
3)创建StreamBuilder用于接收流式数据
StreamBuilder(
stream: _streamController.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text('异步数据:${snapshot.data}');
} else if (snapshot.hasError) {
return Text('发生错误:${snapshot.error}');
} else {
return const Text('加载中...');
}
})
4)通过按钮点击触发模拟接口请求
ElevatedButton(
onPressed: () {
getStreamData();
},
child: const Text("stream get async data.")),
5)完整代码
/*年轻人,只管向前看,不要管自暴自弃者的话*/
import 'dart:async';
import 'package:flutter/material.dart';
///create by itz on 2024/8/16 15:46
///desc :
class StreamPage extends StatefulWidget {
const StreamPage({super.key});
@override
State<StreamPage> createState() => _StreamPageState();
}
class _StreamPageState extends State<StreamPage> {
// 创建控制器
final StreamController _streamController = StreamController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Stream"),
),
body: _widget(),
);
}
Widget _widget() {
return Container(
margin: const EdgeInsets.all(16),
child: ListView(
children: [
ElevatedButton(
onPressed: () {
getStreamData();
},
child: const Text("stream get async data.")),
StreamBuilder(
stream: _streamController.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text('异步数据:${snapshot.data}');
} else if (snapshot.hasError) {
return Text('发生错误:${snapshot.error}');
} else {
return const Text('加载中...');
}
})
],
),
);
}
getStreamData() async {
for (int i = 0; i < 10; i++) {
await Future.delayed(const Duration(seconds: 1));
// 发送值
_streamController.sink.add(i);
}
await Future.delayed(const Duration(seconds: 1));
// 发送值
_streamController.sink.add("done");
}
}
2、事件总线
1)创建EventBus单例类
import 'dart:async';
///create by itz on 2024/8/16 15:54
///desc :
class EventBus {
static final EventBus _instance = EventBus._internal();
factory EventBus() => _instance;
EventBus._internal();
}
2)使用 broadcast() 方法创建了一个可以实时广播事件的 StreamController
final _controller = StreamController<dynamic>.broadcast();
3)创建 get stream,发送事件,关闭控制器等方法
Stream get stream => _controller.stream;
void fire(dynamic event) {
_controller.sink.add(event);
}
void dispose() {
_controller.close();
}
4)使用EventBus,设置EventBus事件监听
EventBus().stream.listen((event) {
setState(() {
eventInfo = event;
});
});
5)发送EventBus事件
sendEvent(String event) {
EventBus().fire(event);
}
6)通过按钮点击触发发送事件
ElevatedButton(
onPressed: () {
sendEvent("cat");
},
child: const Text("send Event.")),
Text(eventInfo),
7)完整EventBus代码
import 'dart:async';
///create by itz on 2024/8/16 15:54
///desc :
class EventBus {
static final EventBus _instance = EventBus._internal();
factory EventBus() => _instance;
EventBus._internal();
// 使用 broadcast() 方法创建了一个可以实时广播事件的 StreamController
final _controller = StreamController<dynamic>.broadcast();
Stream get stream => _controller.stream;
void fire(dynamic event) {
_controller.sink.add(event);
}
void dispose() {
_controller.close();
}
}
8)完整EventBusPage代码
import 'package:async_test/util/EventBus.dart';
import 'package:flutter/material.dart';
///create by itz on 2024/8/16 16:01
///desc :
class EventBusPage extends StatefulWidget {
const EventBusPage({super.key});
@override
State<EventBusPage> createState() => _EventBusPageState();
}
class _EventBusPageState extends State<EventBusPage> {
String eventInfo = "";
@override
void initState() {
// TODO: implement initState
super.initState();
EventBus().stream.listen((event) {
setState(() {
eventInfo = event;
});
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
EventBus().dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("EventBus"),
),
body: Container(
margin: const EdgeInsets.all(16),
child: ListView(
children: [
ElevatedButton(
onPressed: () {
sendEvent("cat");
},
child: const Text("send Event.")),
Text(eventInfo),
],
),
),
);
}
sendEvent(String event) {
EventBus().fire(event);
}
}
Stream 适用于处理持续产生数据的异步操作,而 async/await 适用于一次性获取结果的异步操作。两者使用区别包括控制流、数据处理、使用场景和代码结构。
Provider 与 Stream 区别在于使用 Provider 时状态可以被存储起来,而 Stream 不会存储。选择使用哪种取决于需求和代码结构的复杂度。