<>Flutter 异步编程(Future、async、await)


在Android开发中,异步编程是必不可少的,比如网络请求、IO操作等很多都是异步操作,而在Android原生中,有主线程和工作线程的概念,耗时操作都是要放到工作线程中的,ui要在主线程中更新,因此,原生Android开发中对线程的处理是必不可少的,幸运的是,一些第三方库例如Rxjava、RxAndroid让我们的线程切换起来十分的方便。

但是Flutter是基于Datt语言实现的,而Dart中的代码是在一个线程中运行的,因此,Flutter也是单线程模型的。
参考资料可以看官方说明:Dart异步编程 <https://www.dartlang.org/tutorials/language/futures>
这里不禁有一个问题,Flutter为啥要用Dart呢?单线程会不会比多线程的效率低呢?


先不管效率的问题了,实际运行起来速度还是很快的。

也就是说,我们在Flutter中对异步的处理并不是像原生Android那样是多个线程去处理的。
那么,Flutter中是怎么处理异步操作的呢?

Flutter给我们提供了Future对象以及async和await关键字来支持异步编程。
我们首先来看看 Future
<https://api.dartlang.org/stable/2.2.0/dart-async/Future-class.html>

Future是一个抽象类,我们常用的方法如下


Future对象表示异步操作的结果,我们通常通过then()来处理返回的结果
async用于标明函数是一个异步函数,其返回值类型是Future类型
await用来等待耗时操作的返回结果,这个操作会阻塞到后面的代码

<>Flutter中的网络请求

网络请求是非常典型的异步任务,下面我们就来结合网络请求来看看Flutter中的异步是如何使用的。

网络请求的方式有很多,这里我就直接用目前比较好用的DIO网络请求库
<https://github.com/flutterchina/dio/blob/master/README-ZH.md> 了,你也可以使用官方文档中的
网络请求 <https://flutter.dev/docs/cookbook/networking/fetch-data> ,都是可以的。

下面我们来简单用一用网络请求。

这里我使用的聚合上的一个接口

接口地址:
http://v.juhe.cn/toutiao/index?type=keji&key=4c52313fc9247e5b4176aed5ddd56ad7
<http://v.juhe.cn/toutiao/index?type=keji&key=4c52313fc9247e5b4176aed5ddd56ad7>

关于DIO如何使用这里就不讲了,Github上文档很详细,使用起来也很简单。
下面我们直接用:

首先要先导包
import 'package:dio/dio.dart';
请求接口获取数据的方法
/** * 请求接口获取数据 */ Future<Response> getData() async { String url =
"http://v.juhe.cn/toutiao/index"; String key =
"4c52313fc9247e5b4176aed5ddd56ad7"; String type = "keji"; print("开始请求数据");
Response response = await Dio().get(url, queryParameters: {"type": type, "key":
key}); print("请求完成"); return response; }
注意一下几点:

* 网络请求是耗时操作
* 要使用async来标明getData这个函数是一个异步函数
* await 用于等待请求返回的结果,此时会阻塞掉后面的代码,只有当请求结束后面的代码才会执行
* async标注的函数其返回值类型是Future
然后我们就可以在main函数中来接收网络请求后的结果了:
main() { getData().then((result) { print("接口返回的数据是:${result}");
}).whenComplete((){ print("异步任务处理完成"); }).catchError((){ print("出现异常了"); });
print("我是在请求数据后面的代码呦!"); }
我们来看看执行的结果:

这样一来,我们就完成了Flutter中的异步操作了,可以看到,相对于原生Android来讲,Flutter中的异步是非常简单的。

<>Flutter FutureBuilder

FutureBuilder
<https://docs.flutter.io/flutter/widgets/FutureBuilder-class.html>
实际上就是对Future进行封装的一个Widget。我们先来看看他的构造方法
const FutureBuilder({ Key key, this.future, this.initialData, @required
this.builder })
其中,
future接收Future<T>类型的值,实际上就是我们的异步函数,通常情况下都是网络请求函数
initialData 表示在异步函数执行完成之前可以给快照进行使用,简单理解就是初始数据,应该不是很常用
builder:接收一个AsyncWidgetBuilder<T>类型的值,看源码
/// Signature for strategies that build widgets based on asynchronous ///
interaction. /// /// See also: /// /// * [StreamBuilder], which delegates to an
[AsyncWidgetBuilder] to build /// itself based on a snapshot from interacting
with a [Stream]. /// * [FutureBuilder], which delegates to an
[AsyncWidgetBuilder] to build /// itself based on a snapshot from interacting
with a [Future]. typedef AsyncWidgetBuilder<T> = Widget Function(BuildContext
context, AsyncSnapshot<T> snapshot);
AsyncWidgetBuilder为构建器提供了一个AsyncSnapshot对象,我们再来看看AsyncSnapshot的源码


下图是AsyncSnapshot中的属性和方法


AsyncSnapshot中封装了connectionState(连接状态)、data(实际上就是future执行后返回的数据)以及
error(实际上就是future错误时返回的错误信息)

data和error比较好理解,我们主要来看看connectionState
connectionState是一个enum 类型的值,其源码如下
enum ConnectionState { /// Not currently connected to any asynchronous
computation. /// /// For example, a [FutureBuilder] whose
[FutureBuilder.future] is null. none, /// Connected to an asynchronous
computation and awaiting interaction. waiting, /// Connected to an active
asynchronous computation. /// /// For example, a [Stream] that has returned at
least one value, but is not /// yet done. active, /// Connected to a terminated
asynchronous computation. done, }
* none :当前未连接到任何异步计算。
* waiting : 连接成功等待交互
* active :正在交互中,可以理解为正在返回数据
* done :交互完成,可以理解为数据返回完成,此时如果是正确的返回则data就有数据了
搞清楚这些,我们就可以开心的使用FutureBuilder了。

<>Flutter 请求网络数据时显示加载中


一个很常见的需求,在首次进入页面时,此时数据还需要从网络上获取,我们希望在网络请求完成之前显示一个加载页面,请求完成之后再显示数据。此时,我们就可以使用FutureBuilder来完成了

首先是接口请求函数,为了更明显的能看到加载控件的显示,这里的异步请求函数中我延时3秒后再请求数据,代码如下
import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import
'package:flutter_async/widget/loading.dart'; void main() => runApp(MyApp());
class MyApp extends StatelessWidget { // This widget is the root of your
application. @override Widget build(BuildContext context) { return MaterialApp(
title: '新闻列表', theme: ThemeData( primarySwatch: Colors.blue, ), home:
MyHomePage(title: '新闻列表'), ); } } class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key); final String title;
@override _MyHomePageState createState() => _MyHomePageState(); } class
_MyHomePageState extends State<MyHomePage> { @override Widget
build(BuildContext context) { return Scaffold( appBar: AppBar( title:
Text(widget.title), ), body: FutureBuilder( future: _getNews(), builder:
(BuildContext context, AsyncSnapshot<Response> snapshot) { /*表示数据成功返回*/ if
(snapshot.hasData) { Response response = snapshot.data; return
Text("${response.data.toString()}"); } else { return LoadingWidget(); } }, ));
} } /** * 请求接口获取数据 */ Future<Response> _getNews() async { await
Future.delayed(Duration(seconds: 3), () { print("延时三秒后请求数据"); }); String url =
"http://v.juhe.cn/toutiao/index"; String key =
"4c52313fc9247e5b4176aed5ddd56ad7"; String type = "keji"; print("开始请求数据");
Response response = await Dio().get(url, queryParameters: {"type": type, "key":
key}); print("请求完成"); return response; }
运行效果:


下面是demo,需要的可以下载:
flutter_async Demo
<https://download.csdn.net/download/yuzhiqiang_1993/11106514>

如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可。也可以关注我的 Flutter
<https://yuzhiqiang.blog.csdn.net/column/info/31484>
博客专栏,我会不定期的更新,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客
<https://yuzhiqiang.blog.csdn.net/> ,谢谢!

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信