作者 | 弗拉德
起源 | 弗拉德(公众号:fulade_me)
异步申请
在挪动开发过程中很多时候咱们都须要依赖异步申请数据而后再来刷新UI。在用户关上界面的时候,先给出一个Loading提醒,等数据申请实现后,咱们再把数据展现在页面上,这是很常见的操作。
异步申请的益处就是不会阻塞主线程,用户尽管在“等”,然而页面不会卡死。
同步申请不适应于这种状况,同步申请会呈现页面卡死景象,此时用户不能点击(即便点击也没有成果),体验十分不好。
所以大多数时候咱们都是应用异步申请来获取数据
http 库
在Flutter中,咱们能够用http库来做网络申请,它反对异步申请,并且有良好的API接口
应用http库的步骤:
- 在我的项目中,关上
pubspec.yaml
文件 - 找到
dependencies
字段,在上面增加http: ^0.12.2
,其中0.12.2
是版本号 - 而后保留
pubspec.yaml
并执行pub get
命令把咱们要应用的第三方库下载下来
具体 pub get
命令的应用在之前的文章有介绍过
而后在要应用http库的文件外面引入头文件
import 'package:http/http.dart' as http;
发送http申请的代码也比较简单,咱们这里以get
申请为例
http.get("https://cdn.jsdelivr.net/gh/johnson8888/blog_pages/images/request_demo_test.json");
只有传入要申请的地址即可,这里的URL地址是我本人上传的测试文件。
http 异步申请返回后果
后面我晓得http库发送申请是反对异步的,那么异步申请的返回后果咱们该如何接管呢?
- 通过
then
函数获取,在get
申请之后咱们能够间接跟上then
函数来作为回调,在回调外部能够获取到申请的后果
http.get(getURL).then((value) { print(value);});
这样写的确很不便,但当咱们的网络申请很多,并且一个网络申请依赖另外一个网络申请的时候,这个时候就会多个回调函数嵌套在一起(又称为回调天堂
),代码就会显得很凌乱,很不适宜Debug。
- 应用
await
来接管异步操作的后果
var data = await http.get(getURL);
这样写代码就比下面的代码清新多了
然而须要留神的是,如果函数外部有被await
润饰的办法,那么函数应该被async
来润饰,并且返回值须要被Future
润饰,Future
是一个延时计算的对象,在被await
润饰的函数返回的时候能力拿到Future
的具体值。
示例入下:
Future<Map> getData() async { var data = await http.get(getURL); return data.body; }
刷新页面
咱们后面曾经晓得:调用setState()
函数能够刷新页面,所以在http申请之后咱们调用setState()
函数即可刷新页面
http.get(getURL).then((value) { print(value); var data = jsonDecode(data.body); setState(() { /// 此处执行刷新页面的代码 });});
应用FutureBuilder来刷新页面
setState()
诚然是能够刷新页面,然而当咱们页面内有多个网络申请的时候,就会不停的调用setState()
来全量刷新页面,显然这就有点冗余。
Flutter为咱们提供了更好的形式来实现获取数据并且刷新UI的操作,那就是FutureBuilder
来看它的初始化办法
const FutureBuilder({ /// key Key key, /// 异步的操作 this.future, /// 初始化数据 this.initialData, /// 构建UI的函数 @required this.builder,})
由构造函数可见,咱们须要传入future
参数,也就是咱们的耗时操作函数,还须要传入builder
函数
在builder
办法里能够捕捉到两个参数BuildContext context
和AsyncSnapshot snap
其中snap
的属性会携带future
的耗时函数的返回值,也就是说:在耗时操作函数返回后果之后,咱们能够在builder
办法内获取到这一返回值。
所以下面的申请咱们也能够这么来实现:
FutureBuilder( future: getData(), builder: (BuildContext context, AsyncSnapshot snap) { /// 如果没有数据 咱们就显示loading页面 if (snap.hasData == false) { return CircularProgressIndicator(); } else { /// 如果获取到了数据 咱们就初始化一个 ListView来展现获取到的数据 var dataSource = snap.data["tracks"]; return ListView.builder( itemCount: dataSource.length, itemBuilder: (context, index) { return ListTile( title: Text(dataSource[index]["title"]), subtitle: Text(dataSource[index]["cover"]), ); }, ); } },),
在获取到数据之后,咱们通过ListView.builder
来构建一个ListView
并返回,此时就实现了刷新UI的工作
我这里写的比较简单,只是用hasData
来做为判断的根据
其实还有更优雅的做法:应用snap
的另一个属性connectionState
enum ConnectionState { /// 没有异步工作, none, /// 异步工作正在期待 waiting, /// 异步工作正在执行 或者 数据正在传输 active, /// 异步工作曾经终止. done,}
咱们也能够在connectionState
是done
的时候在来判断是否存在数据
如果存在就展现数据!
想体验以上的示例的运行成果,能够到我的Github仓库我的项目flutter_app
->lib
->routes
->http_page.dart
查看,并且能够下载下来运行并体验。