FutureBuilder 的使用
很多时候我们会依赖一些异步数据来动态更新UI,比如在打开一个页面时我们需要先从互联网上获取数据,在获取数据的过程中我们显式一个加载框,等获取到数据时我们再渲染页面;又比如我们想展示Stream(比如文件流、互联网数据接收流)的进度。
FutureBuilder({ this.future, // FutureBuilder依赖的Future,通常是一个异步耗时任务 this.initialData, // 初始数据,用户设置默认数据 @required this.builder, // Widget构建器:该构建器会在Future执行的不同阶段被多次调用 })
builder 构造器参数结构
Function (BuildContext context, AsyncSnapshot snapshot)
示例:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { Future<String> mockNetworkData() async { return Future.delayed(Duration(seconds: 2), () => "这是网络请求的数据。。。"); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: FutureBuilder<String>( future: mockNetworkData(), builder: (BuildContext context, AsyncSnapshot snapshot) { // 请求已结束 if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasError) { // 请求失败,显示错误 return Text("Error: ${snapshot.error}"); } else { // 请求成功,显示数据 return Text("Contents: ${snapshot.data}"); } } else { // 请求未结束,显示loading return CircularProgressIndicator(); } }, ), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
演示效果:
async/await
在 Dart1.9 中加入了 async 和 await 关键字,有了这两个关键字,我们可以更简洁的编写异步代码,而不需要调用 Future 相关的 API。
使用特点
- 被修饰的方法会将一个 Future 对象作为返回值;
- 该方法会同步执行其中的方法的代码直到第一个 await 关键字,然后它暂停该方法其他部分的执行;
- 一旦由 await 关键字引用的 Future 任务执行完成,await 的下一行代码将立即执行。
// 导入io库,调用sleep函数 import 'dart:io'; // 模拟耗时操作,调用sleep函数睡眠2秒 doTask() async{ await sleep(const Duration(seconds:2)); return "Ok"; } // 定义一个函数用于包装 test() async { var r = await doTask(); print(r); } void main(){ print("main start"); test(); print("main end"); }
结果:
main start main end Ok
Stream 与 StreamBuilder
Stream 也是用于接收异步事件数据,和 Future 不同的是,它可以接收多个异步操作的结果(成功或失败)。 也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。 Stream 常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等。
Stream 的使用
void main(){ print("main start"); Stream.fromFutures([ // 1秒后返回结果 Future.delayed(new Duration(seconds: 1), () { return "hello 1"; }), // 抛出一个异常 Future.delayed(new Duration(seconds: 2),(){ throw AssertionError("Error"); }), // 3秒后返回结果 Future.delayed(new Duration(seconds: 3), () { return "hello 3"; }) ]).listen((data){ print(data); }, onError: (e){ print(e.message); },onDone: (){ }); print("main end"); }
结果:
main start main end hello 1 Error hello 3
StreamBuilder 的使用
StreamBuilder正是用于配合Stream来展示流上事件(数据)变化的UI组件。 下面看一下StreamBuilder的默认构造函数:
StreamBuilder({ Key key, this.initialData, Stream<T> stream, @required this.builder, })
可以看到和 FutureBuilder 的构造函数只有一点不同:前者需要一个 future,而后者需要一个 stream。 示例:
Stream<int> counter() { return Stream.periodic(Duration(seconds: 1), (i) { return i; }); } Widget buildStream (BuildContext context) { return StreamBuilder<int>( stream: counter(), // //initialData: ,// a Stream<int> or null builder: (BuildContext context, AsyncSnapshot<int> snapshot) { if (snapshot.hasError) return Text('Error: ${snapshot.error}'); switch (snapshot.connectionState) { case ConnectionState.none: return Text('没有Stream'); case ConnectionState.waiting: return Text('等待数据...'); case ConnectionState.active: return Text('active: ${snapshot.data}'); case ConnectionState.done: return Text('Stream已关闭'); } return null; // unreachable }, ); } return Scaffold( appBar: AppBar( title: Text(widget.title), ), body:Center( child: buildStream(context), ) );
效果:
isolate
Dart 是基于单线程模型的语言。但是在开发当中我们经常会进行耗时操作比如网络请求,这种耗时操作会堵塞我们的代码,所以在 Dart 也有并发机制,名叫 isolate。 APP 的启动入口 main 函数就是一个类似 Android 主线程的一个主 isolate。和 Java 的 Thread 不同的是,Dart 中的 isolate 无法共享内存,类似于 Android 中的多进程。
isolate 与普通线程的区别isolate 神似 Thread,但实际上两者有本质的区别。操作系统内的线程之间是可以有共享内存的,而 isolate 不能。
isolate 工作原理
isolate 创建主要步骤:
- 初始化isolate数据结构
- 初始化堆内存(Heap)
- 进入新创建的isolate,使用跟isolate一对一的线程运行isolate
- 配置Port
- 配置消息处理机制(Message Handler)
- 配置Debugger,如果有必要的话
- 将isolate注册到全局监控器(Monitor)
Dart 本身抽象了 isolate 和 thread,实际上底层还是使用操作系统的提供的 OSThread,Dart isolate 跟 Flutter Runner 是相互独立的,他们通过任务调度机制相互协作。