共计 2552 个字符,预计需要花费 7 分钟才能阅读完成。
作者 | 弗拉德
起源 | 弗拉德(公众号: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
查看,并且能够下载下来运行并体验。