flutter之網絡請求Dio

創建Dio單例類

創建全局的dio單例類,不需要每次請求都創建Dio對象,節省系統開支
創建NetManager類

class NetManager {
  static Dio _dio;
  static Dio getDio(String versionStr, String tokenStr) {
    if (_dio == null) {
      _dio = new Dio();
    }

//請求頭
    Map<String, dynamic> headers = {
      "os": "ios",
      "Content-Type": "application/json;charset=UTF-8",
      "appname": "crm",
      "version": versionStr
    };
    if (tokenStr == null || tokenStr.length == 0) {
      headers.remove("x-token");
    } else {
      headers.putIfAbsent("x-token", () => tokenStr);
    }

//設置請求頭、超時時間等參數
    _dio.options = BaseOptions(
      headers: headers, //application/x-www-form-urlencoded
      contentType: ContentType.parse("application/json;charset=UTF-8"),
      connectTimeout: 15000,
      receiveTimeout: 15000,
    );
    print("token=="+tokenStr.toString());
    print("version=====" + versionStr);

    return _dio;
  }


  /*獲取當前版本號*/
  static Future<String> getVersion() async {
    try {
      PackageInfo packageInfo = await PackageInfo.fromPlatform();
      return packageInfo.version;
    } catch (e) {
      print("獲取版本好錯誤=" + e.toString());
    }
  }

}

創建網絡請求類HttpTools

//請求成功、請求失敗的回調
typedef SuccCallback = Future<void> Function(
    Map<String, dynamic> responseDic, Response response);
typedef FailCallback = Future<void> Function(String errStr, DioError error);

/*區分網絡請求類型get、post*/
enum HttpType {
  type_get,
  type_post,
}



/*圖片上傳類型區分類型*/
enum ImgFileType {
  type_data, //以二進制流形式上傳List<int>
  type_file, //以文件形式上傳
}

/*存放正在loading的context們*/
final List<BuildContext> contextList = List<BuildContext>();

class HttpTools {
  /*put、post網絡請求*/
  static void http(
      BuildContext context,
      HttpType type,
      String url,
      Map<String, dynamic> paraDic,
      SuccCallback succ,
      FailCallback fail) async {
    String urlStr = baseUrl + url; //完整地址,參數是拼接好之后傳過來的,不需要再拼接了

    if (paraDic == null) {
      paraDic = Map();
    }

    try {
      Response response;
      NetManager.getVersion().then((versionStr) {
        //獲取當前版本號。判斷是否需要更新
        Utils.getToken().then((tokenStr) async {
          //獲取當前cookie。判斷是否登錄

          Dio dio = NetManager.getDio(versionStr, tokenStr);

          //根據不同的網絡請求修改參數
          if (
              //url == xxx
          ) {
            //登錄接口和評論接口都是使用formdata格式提交
            dio.options.contentType =
                ContentType.parse("application/x-www-form-urlencoded");
          }

          HttpTools.showLoading(context, true); //顯示loading
          if (type == HttpType.type_get) {
            response = await dio.get(urlStr).catchError((err) {
              HttpTools.showLoading(context, false); //取消loading
              fail(netWrongMsg, err);
            });

            dataProcessing(
                context, dio, urlStr, response, paraDic, succ, fail); //數據處理
          } else if (type == HttpType.type_post) {
            response = await dio.post(urlStr, data: paraDic).catchError((err) {
              HttpTools.showLoading(context, false); //取消loading
              fail(netWrongMsg, err);
            });
            dataProcessing(
                context, dio,urlStr, response, paraDic, succ, fail); //數據處理
          }
        });
      });
    } catch (e) {
      print("url=" + urlStr);
      print("paraDic=" + paraDic.toString());
      print("報錯了" + e.toString());
      fail(e.toString(), DioError());
    }
  }

  /*文件上傳*/
  static void upload(
      BuildContext context,
      String url,
      String name,
      String fileName,
      String primaryType,
      String subType,
      ImgFileType fileType,
      List<int> data,
      File imgFile,
      Map<String, dynamic> paraDic,
      SuccCallback succ,
      FailCallback fail) async {
    String urlStr = baseUrl + url; //完整地址,參數是拼接好之后傳過來的,不需要再拼接了

    if (paraDic == null) {
      paraDic = Map();
    }


    if(fileType==ImgFileType.type_data){//以二進制流形式上傳
      paraDic.putIfAbsent(
          name,
              () => new UploadFileInfo.fromBytes(data, fileName,
              contentType: ContentType(primaryType, subType))
      );
    }else if(fileType==ImgFileType.type_file){//以文件形式上傳
      paraDic.putIfAbsent(name, ()=>UploadFileInfo(imgFile, fileName));
    }




    FormData formData = new FormData.from(paraDic);
    try {
      Response response;
      NetManager.getVersion().then((versionStr) {
        //獲取當前版本號。判斷是否需要更新
        Utils.getToken().then((tokenStr) async {

          Dio dio = NetManager.getDio(versionStr, tokenStr);
          
          
          dio.options.contentType = ContentType.parse("multipart/form-data");

          HttpTools.showLoading(context, true); //顯示loading
          //獲取當前cookie。判斷是否登錄
          response = await dio
              .post(urlStr, data: formData)
              .catchError((err) {
            HttpTools.showLoading(context, false);
            fail(netWrongMsg, err);
          });
          dataProcessing(context, dio, urlStr, response, paraDic, succ, fail); //數據處理
        });
      });
    } catch (e) {
      print("url=" + urlStr);
      print("paraDic=" + paraDic.toString());
      print("報錯了" + e.toString());
      debugPrint('debugPrint');
      fail(e.toString(), DioError());
    }
  }

  /*get和post請求獲取到的數據處理*/
  static dataProcessing(BuildContext context,Dio dio, String urlStr, Response response,
      Map<String, dynamic> paraDic, SuccCallback succ, FailCallback fail) {
    //盡量保證url和返回結果一塊打印出來
    print("header===");
    print(dio.options.headers);
    print("url=" + urlStr);
    print("paraDic=" + paraDic.toString());
    print("response=" + response.toString());

    HttpTools.showLoading(context, false); //取消loading






    if (response != null && response.statusCode == 200 ) {

      //網絡請求成功
      if (response.data.isNotEmpty && response.data is Map<String, dynamic>) {
        //獲取Map<String,dynamic>類型的返回數據,我們統一處理
        String errcode = response.data["code"].toString();
        String message = response.data["message"].toString();
        var entity = response.data["data"];
//        bool success = response.data["success"];
        bool success = errcode.isNotEmpty && errcode == "200" ? true : false;

        if (success == true) {
          //請求成功
          if (entity is Map<String, dynamic>) {
            //data是字典
            succ(entity, response);
          } else if (entity is List) {
            //data是數組
            succ({kUndefineKey: entity}, response);
          } else if (entity is String) {
            //data是字符串
            succ({kUndefineKey: entity}, response);
          } else if (entity is num) {
            //data是數值類型
            succ({kUndefineKey: entity}, response);
          } else {
            //未知情況按照成功處理
            succ({}, entity);
          }
        } else {
          if (errcode == "401") {
            //token超時
            Fluttertoast.showToast(msg: "登錄超時,請重新登錄");
            LoginModel.requestLogoutFun(context); //退出登錄的接口,通知后臺我退出登錄了
            LoginModel.logoutSucc().then((_){//清除本地token
//              RouteHelper.pushWidget(context,MyHomePage(0), replaceRoot: true);
            Navigator.of(context).pushAndRemoveUntil(new MaterialPageRoute(builder: (ctx){
              return new LoginPage();
            }), (Route route)=>false);
            });

          }
//          else if (errcode == "600") {
//            print("版本更新");
//          }
          else {
            //
            if (message.isEmpty || message.length == 0) {
              fail(netWrongMsg, DioError());
            } else {
              //未知狀態嗎按照錯誤情況處理
              fail(message, DioError());
            }
          }
        }
      } else {
        //返回數據不是Map<String,dynamic>類型的,我們不統一處理,但是也按照成功的情況處理
//        succ(Map(), response);
        fail(netWrongMsg, DioError());
      }
    } else {
      //此次網絡請求不通
      fail(netWrongMsg, DioError());
    }
  }

  /*loading*/
  static void showLoading(BuildContext context, bool isShow) {
    if (isShow == true) {
      //a7c07
      bool isContain = false;
      contextList.forEach((c) {
        if (c.widget.toString() == context.widget.toString()) {
          isContain = true;
        }
      });
      if (!isContain) {
        print("顯示loading");
        contextList.add(context);
//        print("數組長度"+contextList.length.toString());
//        contextList.forEach((c){
//          print("數組元素=="+c.widget.toString());
//        });
        showDialog(
            context: context,
            barrierDismissible: false,
            builder: (BuildContext c) {
              return SpinKitFadingCircle(color: Colors.white);
            });
      }
    } else {
      List<BuildContext> removeList = new List();

      contextList.forEach((c) {
        if (context.widget.toString() == c.widget.toString()) {
          print("取消loading");
          removeList.add(c);
          if (Navigator.canPop(c)) {
            Navigator.pop(c);
          }
        }
      });

      removeList.forEach((rc) {
        contextList.remove(rc);
      });
    }
  }
}

關聯實體類文件

創建model

import 'package:json_annotation/json_annotation.dart';

part 'messageItemModel.g.dart';

@JsonSerializable()
class MessageItemModel{
  String id = "";//這條消息的id
  String toUserid = "";//這條消息是針對誰的用戶id
  String from = ""; //這條消息是誰發起的用戶id
  String infoDesc = "";//描述信息
  String createBy = "";//創建人
  String createDate = "";//創建時間
  String read = "";//是否已讀 0未讀

  String delFlag = "";

  MessageItemModel(this.id, this.toUserid, this.from, this.infoDesc,
      this.createBy, this.createDate, this.read, this.delFlag);



  factory MessageItemModel.fromJson(Map<String, dynamic> json) =>
      _$MessageItemModelFromJson(json);

  Map<String, dynamic> toJson() => _$MessageItemModelToJson(this);

}

使用

    HttpTools.http(context, HttpType.type_post, requestGetMyInfosAction, {"userId":userId,"PageNo":PageNo,"PageSize":PageSize}, (dic,response){

      if(dic!=null && dic["data"]!=null){
        MineMessageModel model = MineMessageModel.fromJson(dic["data"]);
        model.message = dic["message"];
        succ(model);
      }else{
        fail(netWrongMsg);
      }
    }, (errStr,error){
      fail(errStr);
    });

此時下面代碼報錯,沒關系,先這樣寫

part 'messageItemModel.g.dart';

在終端的項目根目錄執行

flutter packages pub run build_runner build

此時生成了一個messageItemModel.g.dart文件,報錯解決了,這個類里邊的代碼是自動生成的,不要手動修改,否則運行錯誤

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'messageItemModel.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

MessageItemModel _$MessageItemModelFromJson(Map<String, dynamic> json) {
  return MessageItemModel(
      json['id'] as String,
      json['toUserid'] as String,
      json['from'] as String,
      json['infoDesc'] as String,
      json['createBy'] as String,
      json['createDate'] as String,
      json['read'] as String,
      json['delFlag'] as String);
}

Map<String, dynamic> _$MessageItemModelToJson(MessageItemModel instance) =>
    <String, dynamic>{
      'id': instance.id,
      'toUserid': instance.toUserid,
      'from': instance.from,
      'infoDesc': instance.infoDesc,
      'createBy': instance.createBy,
      'createDate': instance.createDate,
      'read': instance.read,
      'delFlag': instance.delFlag
    };

用到了json_annotation和json_serializable
(json_annotation)[https://pub.dev/packages/json_annotation]
(json_serializable)[https://pub.dev/packages/json_serializable]

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374