在 Dart 中,没有多线程的概念,所谓的异步操作全部都是在一个线程里面执行的, 并且不会造成卡顿的原因就是事件循环(Event Loop),
如下图所示,在程序的运行过程中,会有两个事件
补充上图:Micortask Queue 为空 才会执行 EventQueue ,EventQueue 为空时程序结束,实际上,事件循环从启动的之后会一直执行。
在程序执行过程中,如果有异步操作,这个操作就会添加到队列中,当发现队列不为空时,就会然后不断的从队列中取出事件在执行
Microtask Queue
一个顶级的队列,只要这个队列里面不是空的,就一定会执行该队列中的任务,
scheduleMicrotask(() { print("Hello Flutter"); });
Future.microtask() //内部调用的也是上面的函数
但是需要注意的是,一般的实战中,我们不会手动给这个队列里面添加事件,该队列一般都是由 Dart 自己来处理的。
Event Queue
普通的事件队列,比 Microtask Queue 低了一个等级,在 Microtask Queue 中没有任务的时候才会执行该队列中的任务
需要异步操作的代码都会放在 EventQueue 中执行,例如:
Future((){ print('这里会被放在 EventQueu 中执行'); }) Future.delayed(Duration(seconds: 1), () { print('这里会被放在 EventQueu 中执行'); });
直接执行的代码
Future.sync(() => print('Hello')); Future.value(() => print('world')); xxx.then()
Future
Flutter 相当于是一个盒子,内部的代码最终会交给 EventQueue 来执行,Future 的状态大致可分为三种,如下:
Future(() { print('未完成状态'); }) .then((value) => print('已完成状态')) .catchError((value) => print('异常状态'));
我们程序中的大部分异步操作都是围绕着这三种状态进行的。
Future 常用的函数
Future.error() Future(() { return Future.error(Exception()); }).then((value) => print('已完成状态')).catchError((value) => print('异常状态'));
创建一个以异常结束的 Future,上面代码最终会执行到 catchError 中。
Future.whenComplete()
类似于 try catch 后面的 finnaly,无论成功和失败,最终都会执行到这里
Future.them 链式调用
//在 them 中可以接继续返回值,该值会在下一个链式的 then 调用中拿到返回的结果 getNetData().then((value) { //支持成功到此处 print(value); return "data1"; }).then((value) { print(value); return "data2"; }).then((value) { print(value); }).catchError((error) { //执行失败到此处 print(error); }).whenComplete(() => print("完成"));
Future.wait()
如果要等到多个异步任务都结束之后再进行一些操作,可以使用 Future.wait
Future.wait([getNetData(), getNetData(), getNetData()]).then((value) { value.forEach((element) { print(element); }); });
Future.delayed()
延时指定的时间后在执行
Future.delayed(Duration(seconds: 3), () { return "3秒后的信息"; }).then((value) { print(value); });
async,await
async:用来表示函数是异步的,定义的函数会返回一个 Future 对象,可以使用 then 添加回调函数
await :后面是一个 Future,表示等待改异步任务的完成,异步完成之后才会继续往下走,await 必须出现在 async 的内部
void main() { print("start ----------->"); getNetData().then((value) => print(value)); print("end -------------->"); } // async 会将返回的结果封装为 Future 类型 getNetData() async { var result1 = await Future.delayed(Duration(seconds: 3), () { return "网络数据1"; }); var result2 = await Future.delayed(Duration(seconds: 3), () { return "网络数据2"; }); return result1 + "-----" + result2; }
FutureBuilder
监听一个 Future,以 Future 的状态来进行 setState
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return FutureBuilder( future: Future.value(10), builder: (BuildContext context, AsyncSnapshot<dynamic> snap) { return DemoWidget() }); } }
构造
future :接受一个 future,当 future 的值发生变化之后,就会自动调用下面的 build 函数,
initialData:初始值,在 future 没完成的时候可以暂时使用该值,该值会放在 AsyncSnapshot 的 data 中,在 future 未完成的时候可以使用该值。在 future 出错的时候,该值会被 AsyncSnapshot 从 data 中删掉
builder:返回一个 Widget
AsyncSnapshot 用来保存 future 最近的状态,这个状态只有两个情况,一种是有数据 data,一种是错误状态 error。 AsyncSnapshot 中还有 ConnectionState 状态,分别表示的是 none :没有传递 future,waiting:等待中,active:TODO ,done :表示已经完成
FutureBuilder 的作用就是根据 future 的状态来判断当前页面需要显示哪些 widiget,例如 future 在等待的时候显示加载框,完成之后显示内容等。
需要注意的一点是当状态为 done 是,可能会有两种情况,一种是 future 成功了,另一种是 future 失败了,内部有异常,这个时候就不应该获取 data,而是判断 snap.hasData 来进行判断。
示例
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return FutureBuilder( future: Future.value(10), builder: (BuildContext context, AsyncSnapshot<dynamic> snap) { if (snap.connectionState == ConnectionState.waiting) { return CircularProgressIndicator(); } if (snap.connectionState == ConnectionState.done) { if (snap.hasData) { return DemoWidget(); } else { return Text(snap.error); } } throw "should not happen"; }); } } //在精简一些 class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return FutureBuilder( future: Future.value(10), builder: (BuildContext context, AsyncSnapshot<dynamic> snap) { //如果有数据 if (snap.hasData) { return DemoWidget(); } //如果发生错误 if (snap.hasError) { return Text(snap.error); } // 等待中,显示加载框 return CircularProgressIndicator(); }); } }
源码浅析
/// State for [FutureBuilder]. class _FutureBuilderState<T> extends State<FutureBuilder<T>> { //.... @override void initState() { //如果没有初始值,则先设置Wie none 状态,如果有,则传入初始值 _snapshot = widget.initialData == null ? AsyncSnapshot<T>.nothing() : AsyncSnapshot<T>.withData(ConnectionState.none, widget.initialData as T); _subscribe(); } @override void didUpdateWidget(FutureBuilder<T> oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.future != widget.future) { //.... _subscribe(); } } void _subscribe() { if (widget.future != null) { final Object callbackIdentity = Object(); _activeCallbackIdentity = callbackIdentity; widget.future!.then<void>((T data) { if (_activeCallbackIdentity == callbackIdentity) { //任务执行完成,将数据传给 _snapshot ,并刷新 setState(() { _snapshot = AsyncSnapshot<T>.withData(ConnectionState.done, data); }); } }, onError: (Object error, StackTrace stackTrace) { if (_activeCallbackIdentity == callbackIdentity) { setState(() { //出现错误 _snapshot = AsyncSnapshot<T>.withError(ConnectionState.done, error, stackTrace); }); } assert(() { //判断调试状态 if(FutureBuilder.debugRethrowError) { Future<Object>.error(error, stackTrace); } return true; }()); }); //没有完成则是等待状态 _snapshot = _snapshot.inState(ConnectionState.waiting); } }
源码其实很简单,仔细看一下就知道整个流程了
StreamBuilder
介绍
上面的 FutureBuilder 只能给我们一个值,而 StreamBuildder 可以给我们一连串的值 ,例如:
final stream = Stream.periodic(Duration(seconds: 1), (count) => count++); stream.listen((event) { print(event); });
示例
class _MyHomePageState extends State<MyHomePage> { final stream = Stream.periodic(Duration(seconds: 1), (count) => count++); @override Widget build(BuildContext context) { return Container( alignment: Alignment.center, color: Colors.white, child: DefaultTextStyle( style: TextStyle(fontSize: 30, color: Colors.black), child: StreamBuilder( stream: stream, builder: (BuildContext context, AsyncSnapshot<dynamic> snap) { switch (snap.connectionState) { case ConnectionState.none: return Text("NONE:没有数据流"); break; case ConnectionState.waiting: return Text("WAITING:等待数据流"); break; case ConnectionState.active: if (snap.hasData) { return Text(snap.data.toString()); } if (snap.hasError) { return Text(snap.error.toString()); } break; case ConnectionState.done: return Text("DONE:数据流已关闭"); break; } return CircularProgressIndicator(); }), ), ); } }
其实和 FutureBuilder 差不多,只不过多了一个 active 状态,这个状态在上面没有说是因为用不到**,在这里的意思指的就是数据流是否为活跃的**,如果是活跃的,则就可以获取他的值了
创建方式及常用的函数
使用 Stream.periodic 的方式来创建一个数据流,如上面的示例所示
读取文件的方式
File("").openRead().listen((event) { })
将读取的文件信息以数据流的方式转给我们
使用 StreamController
final controller = StreamController(); controller.stream.listen((event) { print('$event'); }); controller.sink.add(12); controller.sink.add(13); controller.sink.add(14); controller.sink.add(15); controller.sink.addError("Error"); //关闭后则不能进行任何添加操作 controller.close();