很多時候我們有這樣一個需求,需要在網絡請求完了之後再去渲染頁面,尤其是在一個界面有多個相關網絡請求的時候需要處理。
這裏不得不提到一個系統的組件FutureBuilder,我們直接來看用法。
FutureBuilder用法
單網絡請求:
@override
Widget buildWidget(BuildContext context, Store<UserState> store) {
// TODO: implement buildWidget
return Scaffold(
body: FutureBuilder(
future: _futureBuilderFuture,
builder: (BuildContext context, AsyncSnapshot snapShot) {
print('connectionState:${snapShot.connectionState}');
if (snapShot.connectionState == ConnectionState.waiting) {
return Text('Loading...');
} else if (snapShot.connectionState == ConnectionState.done) {
print(snapShot.hasError);
print('data:${snapShot.data}');
if (snapShot.hasError) {
return Text('Error: ${snapShot.error}');
}
return ListView(
...
其中第一個參數 future對應的是一個具有Future返回值的方法,這個方法可以是一個網絡請求,比如
Future<CommonModel> fetchPost() async {
final response = await http.get('http://www.devio.org/io/flutter_app/json/test_common_model.json');
Utf8Decoder utf8decoder = Utf8Decoder(); //fix 中文亂碼
var result = json.decode(utf8decoder.convert(response.bodyBytes));
return CommonModel.fromJson(result);
}
那我們寫法是
future: fetchPost(),
避免重複網絡請求:
但是這樣寫會有一個問題,那就是當我們調用setstate的時候,將會刷新整個FutureBuilder,結果會是fetchPost這個方法會調用多次,造成了不必要的請求和資源浪費。所以我們建議這樣寫
var _futureBuilderFuture;
@override
void initState() {
_futureBuilderFuture = getDatas();
super.initState();
}
引用的時候
future: _futureBuilderFuture,
這樣當我們調用setstate的時候,就不會有多次網絡請求了
下來還有個問題,剛纔是界面只有一個網絡請求,那麼假如有多個呢,寫法如下:
Future getDatas() async {
return Future.wait([getDelegationData(), getData()]);
}
多網絡請求:
其中getDelegationData ,getData是兩個單獨的網絡請求,寫法如下
Future getData() async {
var data = {
'iReq': "BTC_USDT",
};
TradeInfo response = await TradeService.getData(this, data.toString());
}
getDelegationData一樣,不再給出,這樣的話等兩個請求都結束之後會返回一個新的Future到我們的FutureBuilder
if (snapShot.connectionState == ConnectionState.waiting) {
return Text('Loading...');
} else if (snapShot.connectionState == ConnectionState.done) {
print(snapShot.hasError);
print('data:${snapShot.data}');
if (snapShot.hasError) {
return Text('Error: ${snapShot.error}');
}
這裏的話就用到了snapShot的幾種狀態,用來判斷網絡請求處於哪一個階段,等待(請求中),done完成,包括如果請求有異常的話,我們可以打印出來 return Text(‘Error: ${snapShot.error}’);
注意事項:
這裏有一個情況就是我們在調用Future.wait([getDelegationData(), getData()]);的時候,請求網絡的順序是按參數的先後順序執行的,先走getDelegationData請求,再走getData,但是返回數據結果的順序卻不能保證,因爲是根據請求需要的時間決定的,異步的,所以我們儘量把數據處理放在ConnectionState.done之後再處理。
多網絡請求如何控制順序:
另外如果你的網絡請求有邏輯關係,比如第一個接口的返回值要當做第二個接口的請求參數,那麼寫法如下
Future testThen2() asyn {
Future getDatas() async {
return getDelegationData().then((e){
getData();
});
}
// 請求順序是從外層到裏層即 getDatas=====getDelegationData===getData
以上over,有不足之處請提出改正