創建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]