Dart是单线程模型,我们写的代码都运行在同一个线程中。如果做了耗时操作,会使应用程序阻塞。Dart中使用Future和Stream编写异步任务。
Future
Future是一个不会马上完成的计算过程,说的通俗一点就是一个异步执行过程,需要配合async和await一起使用。不会阻塞在此之后的代码,等待计算完成后才会返回结果。
类似于JavaScript中的Promise
和async
、await
。
用法
void main() { requestApi(); doSomething1(); doSomething2(); } doSomething1() { print("doSomething1"); } doSomething2() { print("doSomething2"); } /// 异步请求数据 Future requestApi() async { .... return }
由于requestApi()
是个异步函数,程序运行后,不会等待函数执行完成,下面的代码也会立即开始执行。
等待返回结果
如果想在异步函数返回结果后再做其他操作,可以使用then()
方法来监听。
void main() { requestApi().then((value) { /// 结果返回,开始处理 showApiData(value); }); print("程序开始运行..."); } ............ showApiData(dynamic value){ print("展示获取的数据: $value"); }
FutureBuilder
const FutureBuilder({ Key? key, this.future, this.initialData, required this.builder, })
FutureBuilder会基于传入的future的返回结果来构建Widget。
使用示例
一般用于网络请求后更新UI。
class FutureBuilderDemo extends StatefulWidget { const FutureBuilderDemo({Key key}) : super(key: key); @override _FutureBuilderDemoState createState() => _FutureBuilderDemoState(); } class _FutureBuilderDemoState extends State<FutureBuilderDemo> { Future<String> futureData; @override void initState() { super.initState(); /// ui初始化时开始网络请求数据 futureData = getData(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('FutureBuilder 测试'), ), body: Container( child: Center( child: FutureBuilder<String>( future: futureData, builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { return Text("获取的数据==${snapshot.data}"); } else if (snapshot.hasError) { return Icon(Icons.error_outline); } else { return CircularProgressIndicator(); } }), ), ), ); } Future<String> getData() async { /// 模拟网络请求,等待5秒返回结果 await Future.delayed(Duration(seconds: 5)); /// 返回一个错误 // return Future.error("error"); /// 返回一个成功的结果 return "Hello,world"; } }
Stream
Stream是一系列异步事件的序列,相当于一个异步的跌代器(Iterable)。不同于Future只是一个事件执行过程,Stream可以发送执行多个事件。使用场景不同。
用法
创建方式有2种,一个是单订阅的Stream,一种是能多订阅的流,也就是可以广播。
订阅后(listen)会返回一个StreamSubscription,就是一个观察者。
2种方式的构造方法都有一个可选参数sync
,默认为false。
.......... bool sync = false}) { return sync ? _SyncStreamController<T>(....) : _AsyncStreamController<T>(...);
通过源码可以看出,sync
为false创建的是一个异步事件StreamController, sync
为true时创建的是一个同步StreamController。因为大部分场景下使用Stream都是为了异步,所以我们直接不传入即可。
单订阅
/// 直接使用构造函数 StreamController<String> _controller = StreamController(); StreamSubscription subscription = _controller.stream.listen((event) { print("subscription 接收到 $event"); });
广播订阅
void main() { /// 使用工厂方法构造可广播的Controller StreamController _controller = StreamController.broadcast(); /// 使用多个观察者订阅同一个Stream. StreamSubscription subscription1 = _controller.stream.listen((event) => print("sub1 接收到 $event")); StreamSubscription subscription2 = _controller.stream.listen((event) => print("sub2 接收到 $event")); StreamSubscription subscription3 = _controller.stream.listen((event) => print("sub3 接收到 $event")); /// 发送事件后,所有已订阅的观察者的都能接收到事件。 _controller.add("Hello"); }
运行多次,打印结果都如下不变:
sub1 接收到 Hello sub2 接收到 Hello sub3 接收到 Hello Process finished with exit code 0
结论:
事件订阅(
listen
)的越早,接收到事件的优先级越高。
释放资源
使用完事件后或者在Flutter中Widget关闭时,记得也同时关闭Stream。
_controller.stream.listen((event) {}, onDone: () => print("收到onDone事件")); _controller.close(); subscription.cancel();
关闭后会自动触发onDone回调方法。
StreamBuilder
在界面中,一般使用StreamBuilder来来配合Stream使用。可以实现多状态界面。
使用示例
/// 定义3种ui状态 enum UIState { type_1, type_2, type_3 } class StreamBuilderDemo extends StatefulWidget { const StreamBuilderDemo({Key key}) : super(key: key); @override _StreamBuilderDemoState createState() => _StreamBuilderDemoState(); } class _StreamBuilderDemoState extends State<StreamBuilderDemo> { StreamController<UIState> _controller; @override void initState() { super.initState(); /// 初始化controller _controller = StreamController(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('StreamBuilder测试'), ), body: Container( // height: double.infinity, child: Center( child: StreamBuilder<UIState>( /// 传入stream stream: _controller.stream, builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { /// hasData代表有接收到事件 var data = snapshot.data; Widget widget; ///根据返回不回的类型,展示不同的图片 switch (data) { case UIState.type_1: widget = Icon(Icons.timer, size: 100); break; case UIState.type_2: widget = Icon(Icons.done, size: 100); break; case UIState.type_3: widget = Icon(Icons.ac_unit, size: 100); break; } return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ widget, Text("$data"), ], ); } else if (snapshot.hasError) { /// 接收到错误事件 return Icon(Icons.error_outline_rounded, size: 100); } else { /// 什么都没有,代表没还有接收到事件 return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(), Text("初始化中,还没接收到收到状态"), ], ); } }), ), ), floatingActionButton: FloatingActionButton( onPressed: () => generateState(), child: Icon(Icons.add)), ); } /// 随机生成不同的状态,发送事件 generateState() { var randomIndex = Random().nextInt(UIState.values.length); _controller.add(UIState.values[randomIndex]); } @override void dispose() { super.dispose(); /// 回收资源 _controller.close(); } }