强烈建议先看下这个 Dart异步编程
Future
Future表示在接下来的某个时间的值或者错误,Flutter中借助Future实现 Future有两种状态:
- 执行中
- 执行完成(包括成功和失败)
Future后续Api
先看看Future后续操作
main() {
Future((){
return '你好';//future返回了值
}).then((value) {
print(value);//then中接受到返回的值
print('catchError');
})//当then中接受onError(e){}时catchError不执行
.catchError((e){//接受中间过程发生的异常
print('catchError');
})
.whenComplete((){//失败成功后都会回调
print('whenComplete');
});
}
复制代码
结果
你好
catchError
whenComplete
复制代码
Future 常见api
Future.value()
返回一个携带值的Future对象
main() {
print('start');
Future.value('哈哈哈').then((value) => print(value));
print('end');
}
复制代码
结果
start
end
哈哈哈
复制代码
Future.error() 创建一个以错误为完成状态的Future(可以携带任意类型值)
main() {
print('start');
Future.error(Exception("发生异常")).then((value) => print(value)).catchError((e){
print(e.toString());
});
print('end');
}
复制代码
结果
start
end
Exception: 发生异常
复制代码
Future.delayed()延迟多长时间后执行(时间不一定准确,如果上个任务是个耗时操作,并不一定会是延迟的时间)
main() {
print('start');
Future.delayed(Duration(seconds: 2),(){
return '延迟两秒';
}).then((value){
print(value);
print(DateTime.now().second);
}).catchError((e){
print(e.toString());
});
print('end');
print(DateTime.now().second);
}
复制代码
结果
start
end
11
延迟两秒
13
复制代码
如果在下面加上
Future((){
sleep(Duration(seconds: 5));
}).then((value) => print(DateTime.now().second));
复制代码
结果是5s后执行
start
end
9
14
延迟两秒
14
复制代码
Future.wait([] futures)
等待所有的future完成后再一起返回,如果中间过程中又任意一个Future出错,则整个任务失败
main() {
Future.wait([
Future.value("哈哈哈"),
Future.value(222),
Future.delayed(Duration(seconds: 2))
])
.then((value) => print(value));
}
复制代码
结果
[哈哈哈, 222, null]
复制代码
有一个Future出错
main() {
Future.wait([
Future.delayed(Duration(seconds: 2)),
Future.error(222),
])
.then((value) => print(value))
.catchError((e){print("catchError");});
}
复制代码
整个任务失败
catchError
复制代码
Future.microtask
如果你看过了文章顶部的连接 应该知道 microtask 比event的优先级要高,当非future代码执行完成之后会有限轮训microtask的消息队列,处理其中的microtask再去轮训event
main() {
Future((){print("0000000");}).then((value) => print('11111111'));
Future.value('2222222').then((value) => print(value));
Future.microtask(() =>print("3333333")).then((value) => print('444444444'));
}
复制代码
执行结果
2222222
3333333
444444444
0000000
11111111
复制代码
哎?为什么Future.value()比Future.microtask还快?看来下源码,有一句关键的
....
上面有一堆调用,省略...
void _asyncCompleteWithValue(T value) {
_setPendingComplete();
_zone.scheduleMicrotask(() {
_completeWithValue(value);
});
}
复制代码
所以Future.value()和Future.error(),相当于整了个microtask,所以...
Future.sync()
立马执行...跟同步代码一样
main() {
Future((){print("0000000");}).then((value) => print('11111111'));
Future.value('2222222').then((value) => print(value));
Future.microtask(() =>print("3333333")).then((value) => print('444444444'));
Future.sync(() => print("55555555"));
}
复制代码
结果
55555555
2222222
3333333
444444444
0000000
11111111
复制代码
当main函数开始执行时,1行:发送个event,2行发送个microtask,3行发送个microtask,4行立马执行,所以结果就是如上喽
Future.any([])
在Future的list中只要有一个Future执行完成返回了结果.then()中就是该Future的结果,如果list中出错的先完成 那也会回调到then()中
main() {
Future.any([
Future.value('0000000'),
Future.value('11111111'),
// Future.error("2222222")
])
.then((value) => print(value));
}
复制代码
结果
0000000
复制代码
Future.forEach()
main() {
Future.forEach([
Future.error("2222222"),
Future.value('0000000'),
Future.value('11111111'),
], (element) => print(element)).catchError((e){
print('catchError');
}).whenComplete(() => print('whenComplete'));
}
复制代码
结果
Instance of 'Future<dynamic>'
Instance of 'Future<String>'
Instance of 'Future<String>'
Unhandled exception:
2222222
复制代码
Future.while()
当返回false是停止执行
main() {
Future.doWhile((){
print('1111111');
Future.value('0000000');
Future.value('11111111');
return false;
});
}
复制代码
1111111
复制代码
async 和await
async 和await 是为了方便Future相关Api的语法糖
- async 标记的函数一般会返回future对象,
- await 就是用同步方式的代码来执行异步操作
- 使用await字段时函数必须加async字段
首先看一个微信登录的例子
main() {
getWxInfo()
.then((value) => getUserInfo(value))
.then((value) => saveUserDate(value))
.then((value) => print(value));
}
Future getWxInfo(){
return Future.value("获得了微信UID");
}
Future getUserInfo(String param){
return Future.value("$param->获得了用户信息");
}
Future saveUserDate(String param){
return Future.value("$param->存储了了用户信息");
}
复制代码
结果
获得了微信UID->获得了用户信息->存储了了用户信息
复制代码
使用async和await 字段
main() async {
String uid= await getWxInfo();
String uinfo=await getUserInfo(uid);
String save=await saveUserDate(uinfo);
print(save);
}
Future getWxInfo(){
return Future.value("获得了微信UID");
}
Future getUserInfo(String param){
return Future.value("$param->获得了用户信息");
}
Future saveUserDate(String param){
return Future.value("$param->存储了了用户信息");
}
复制代码
结果当然一样喽,这样就是使用同步代码的方式实现异步编程
单线程的Dart语言会不会卡?为什么现在感觉一点也不卡呢?
Dart的IO操作是交给运行时和系统,所在进行文件读写,网络请求时并不会卡住线程,当有大量的数据运算时比如复杂json数据解析,大量数据模型转换等场景下还是会卡的....
当然也是有解决办法的.....那就是 isolate(这部分还不理解,就不误人子弟了) 看下面链接
Flutter中http请求
Dio是目前比较牛批的一个第三方http库,很多地方借鉴了Okhttp的思想,比较容易上手,看下官网Api即可,等我深入理解这块内容之后 我再开源个基于Dio的封装吧
FutureBuilder
- 创建一个future对象(代码不是重点)
Future<HomeTest> _post() async {
Map<String ,dynamic> json= await HttpManager()
.getAsync(
url: '/posts/1',
options:
RequestOptions(baseUrl: 'https://jsonplaceholder.typicode.com'),
responseFormat: null);
return HomeTest.fromJson(json);
}
复制代码
- 使用futurebuilder
Container(
height: 800,
child: FutureBuilder<HomeTest>(future: _post(),builder: (BuildContext context, AsyncSnapshot<HomeTest> snapshot) {
if(snapshot.connectionState==ConnectionState.none){
return Text('ConnectionState.none');
}else if(snapshot.connectionState==ConnectionState.waiting){
return Text('ConnectionState.waiting');
}else if(snapshot.connectionState==ConnectionState.active){
return Text('ConnectionState.active');
}else{
return Text('加载完成--${snapshot.data}');
}
},),
)
复制代码
根据AsyncSnapshot执行的状态填充不同的内容,
但是有一个需要注意的是,如果父节点以及之上的节点调用了setState()方法在会从新加载Futurebuilder的post请求,就是重新创建了FutureBuilder,所以要控制好状态和位置
本地存储
在Flutter中在本地存储一些简单的key-value基于shared_preferences插件
使用起来也比较简单
引入到项目,同步项目下载插件,导入相应的包即可使用
_testSharedPreferences() async {
var sp = await SharedPreferences.getInstance();
await sp.setString("key1", 'value');
String value1=sp.get('key1');
String value2=sp.get('key2');
print('value1=$value1;value2=$value2');
}
复制代码
需要注意的是:获取SharedPrefrences实例和setValue时是异步的,返回的是Future对象