一步一步搭建Flutter開發架子-網路請求,非同步UI更新封裝

一天清晨發表於2021-03-02

接上文,這篇文章主要介紹Flutter網路請求, 頁面不同狀態展示的封裝

網路請求

主要使用的是dio庫進行網路請求,引入的第三個庫。對於Flutter的自帶的HttpClient也可以。用習慣了dio還是放不下。或者有興趣的可以自己對於HttpClient封裝一下

引入dio

在pubspec.yaml檔案中加入

dio: ^3.0.10
複製程式碼

引入標頭檔案方式

import 'package:dio/dio.dart';
複製程式碼

簡單封裝使用dio

先分析一下使用場景,比較常見的場景是使用者登入之後獲取到token之後,設定在請求頭中進行請求獲取資料。接下來沿著這個思路設計一下。 新建一個base.dart檔案

import 'package:dio/dio.dart';

Dio initDio() {
  BaseOptions _baseOptions = BaseOptions(
      baseUrl: '設定伺服器地址', connectTimeout: 15000);
  Dio dio = Dio(_baseOptions);
  dio.interceptors
      .add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
    print('走網路請求了設定頭部了');
    options.queryParameters['Authorization'] =
        SpUtil.getString('token', defValue: '');
    return options;
  }));
  return dio;
}
class Api {
  static Dio dio = initDio();

  static Future<Map> requestApi(method, path, data) async {
    Response result;
    try {
      if (method == 'get') {
        result = await dio.get(path, queryParameters: data);
      } else if (method == 'post') {
        result = await dio.post(path, data: data);
      }
      print(result);
      return result.data;
    } on DioError catch (e) {
      print(e);
      if (e == null) {
        return Future.error(Response(data: -1));
      } else if (e.response != null) {
        if (e.response.statusCode >= 300 && e.response.statusCode < 400) {
          return Future.error(Response(data: -1));
        } else {
          result = e.response;
          return Future.value(result.data);
        }
      } else {
        return Future.error(Response(data: -1));
      }
    } finally {
      print('網路請求結束');
    }
  }
}
複製程式碼

以上初始化了dio。具體的請求我們可以再建立檔案。放在一起比較亂。比如首頁的請求放在一起,我的頁面的請求放在一起。應該能理解哈

class ReqHome {
  Future<Map> loginInApi(username, password) {
    return Api.requestApi('post', '/login',
        {"username": username, "password": password});
  }
  static Future<Map> getSwiperApi() {
    return Api.requestApi('get', '地址', {});
  }
}
複製程式碼

下面就是呼叫了,已登入為例

 Map result = await ReqHome().loginInApi('使用者名稱', '密碼');
 // 這樣在獲取到token之後在存入到本地
  SpUtil.putString('token', '獲取的token');
複製程式碼

獲取到token之後需要把token設定在header中

 dio.interceptors
      .add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
      
    // 在這新增!!!!!!
    options.queryParameters['Authorization'] =
        SpUtil.getString('token', defValue: '');
        
    return options;
  }));
複製程式碼

頁面不同狀態展示封裝

我是用FutureBuilder來控制頁面顯示不同狀態。首先建立個類common_widget檔案, 線分析一波,頁面狀態分成載入中, 載入完成空資料, 載入完成展示UI,載入失敗。 演示一下載入成功的圖視: 首先定義三個屬性

// final Future networkApi; // 傳進來的網路請求
// final Function onSuccess; // 載入成功之後把資料傳遞出去
// final Widget successWidget; // 載入成功的檢視
複製程式碼

下面是主要程式碼:

@override
  Widget build(BuildContext context) {
    return FutureBuilder<Map>(
        future:
             widget.networkApi,
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          // 請求已結束
          if (snapshot.connectionState == ConnectionState.done) {
            print(snapshot);
            if (snapshot.hasError) {
              // 請求失敗,顯示錯誤
              return _errorView;
            } else {
              // 請求成功,顯示資料
              if (snapshot.data == null || snapshot.data.length == 0) {
                return _emptyView;
              }
              widget.onSuccess();
              return widget.successWidget;
            }
          } else {
            // 請求未結束,顯示loading
            return Center(
              child: CircularProgressIndicator(),
            );
          }
        });
  }
複製程式碼

呼叫程式碼:

 @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('首頁'),
        ),
        body: CommonWidget(
          networkApi: ReqHome.getSwiperApi(),
          successWidget: successWidget(),
          onSuccess: () {},
        ));
  }
複製程式碼

展示錯誤UI

在common_widget檔案中加入程式碼:

///錯誤檢視
  Widget get _errorView {
    return Container(
      width: double.infinity,
      height: double.infinity,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          // Image.asset(
          //   'assets/images/load_error_view.png',
          //   height: 80,
          //   width: 100,
          // ),
          Text("載入失敗,請重試"),
          RaisedButton(
            color: Colors.red,
            onPressed: () {
              setState(() {});
            },
            child: Text(
              '重新載入',
              style: TextStyle(color: Colors.white),
            ),
          )
        ],
      ),
    );
  }
複製程式碼

效果如下:

展示空資料UI

///資料為空的檢視
  Widget get _emptyView {
    return Container(
      width: double.infinity,
      height: double.infinity,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Padding(
            padding: EdgeInsets.only(top: 10),
            child: Text('暫無資料'),
          )
        ],
      ),
    );
  }
複製程式碼

效果圖:

檢視可以根據UI設計去修改,答題結構就是這樣子的。。

one more things。。。。。。

  • 列表資料重新整理載入封裝
  • 一些工具類封裝

相關文章