Flutter如何做到網絡請求(多個網絡請求)完成之後再加載頁面

很多時候我們有這樣一個需求,需要在網絡請求完了之後再去渲染頁面,尤其是在一個界面有多個相關網絡請求的時候需要處理。
這裏不得不提到一個系統的組件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,有不足之處請提出改正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章