創(chuàng)建Dio單例類
創(chuàng)建全局的dio單例類,不需要每次請(qǐng)求都創(chuàng)建Dio對(duì)象,節(jié)省系統(tǒng)開(kāi)支
創(chuàng)建NetManager類
class NetManager {
static Dio _dio;
static Dio getDio(String versionStr, String tokenStr) {
if (_dio == null) {
_dio = new Dio();
}
//請(qǐng)求頭
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);
}
//設(shè)置請(qǐng)求頭、超時(shí)時(shí)間等參數(shù)
_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;
}
/*獲取當(dāng)前版本號(hào)*/
static Future<String> getVersion() async {
try {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
return packageInfo.version;
} catch (e) {
print("獲取版本好錯(cuò)誤=" + e.toString());
}
}
}
創(chuàng)建網(wǎng)絡(luò)請(qǐng)求類HttpTools
//請(qǐng)求成功、請(qǐng)求失敗的回調(diào)
typedef SuccCallback = Future<void> Function(
Map<String, dynamic> responseDic, Response response);
typedef FailCallback = Future<void> Function(String errStr, DioError error);
/*區(qū)分網(wǎng)絡(luò)請(qǐng)求類型get、post*/
enum HttpType {
type_get,
type_post,
}
/*圖片上傳類型區(qū)分類型*/
enum ImgFileType {
type_data, //以二進(jìn)制流形式上傳List<int>
type_file, //以文件形式上傳
}
/*存放正在loading的context們*/
final List<BuildContext> contextList = List<BuildContext>();
class HttpTools {
/*put、post網(wǎng)絡(luò)請(qǐng)求*/
static void http(
BuildContext context,
HttpType type,
String url,
Map<String, dynamic> paraDic,
SuccCallback succ,
FailCallback fail) async {
String urlStr = baseUrl + url; //完整地址,參數(shù)是拼接好之后傳過(guò)來(lái)的,不需要再拼接了
if (paraDic == null) {
paraDic = Map();
}
try {
Response response;
NetManager.getVersion().then((versionStr) {
//獲取當(dāng)前版本號(hào)。判斷是否需要更新
Utils.getToken().then((tokenStr) async {
//獲取當(dāng)前cookie。判斷是否登錄
Dio dio = NetManager.getDio(versionStr, tokenStr);
//根據(jù)不同的網(wǎng)絡(luò)請(qǐng)求修改參數(shù)
if (
//url == xxx
) {
//登錄接口和評(píng)論接口都是使用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); //數(shù)據(jù)處理
} 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); //數(shù)據(jù)處理
}
});
});
} catch (e) {
print("url=" + urlStr);
print("paraDic=" + paraDic.toString());
print("報(bào)錯(cuò)了" + 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; //完整地址,參數(shù)是拼接好之后傳過(guò)來(lái)的,不需要再拼接了
if (paraDic == null) {
paraDic = Map();
}
if(fileType==ImgFileType.type_data){//以二進(jìn)制流形式上傳
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) {
//獲取當(dāng)前版本號(hào)。判斷是否需要更新
Utils.getToken().then((tokenStr) async {
Dio dio = NetManager.getDio(versionStr, tokenStr);
dio.options.contentType = ContentType.parse("multipart/form-data");
HttpTools.showLoading(context, true); //顯示loading
//獲取當(dāng)前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); //數(shù)據(jù)處理
});
});
} catch (e) {
print("url=" + urlStr);
print("paraDic=" + paraDic.toString());
print("報(bào)錯(cuò)了" + e.toString());
debugPrint('debugPrint');
fail(e.toString(), DioError());
}
}
/*get和post請(qǐng)求獲取到的數(shù)據(jù)處理*/
static dataProcessing(BuildContext context,Dio dio, String urlStr, Response response,
Map<String, dynamic> paraDic, SuccCallback succ, FailCallback fail) {
//盡量保證url和返回結(jié)果一塊打印出來(lái)
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 ) {
//網(wǎng)絡(luò)請(qǐng)求成功
if (response.data.isNotEmpty && response.data is Map<String, dynamic>) {
//獲取Map<String,dynamic>類型的返回?cái)?shù)據(jù),我們統(tǒng)一處理
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) {
//請(qǐng)求成功
if (entity is Map<String, dynamic>) {
//data是字典
succ(entity, response);
} else if (entity is List) {
//data是數(shù)組
succ({kUndefineKey: entity}, response);
} else if (entity is String) {
//data是字符串
succ({kUndefineKey: entity}, response);
} else if (entity is num) {
//data是數(shù)值類型
succ({kUndefineKey: entity}, response);
} else {
//未知情況按照成功處理
succ({}, entity);
}
} else {
if (errcode == "401") {
//token超時(shí)
Fluttertoast.showToast(msg: "登錄超時(shí),請(qǐng)重新登錄");
LoginModel.requestLogoutFun(context); //退出登錄的接口,通知后臺(tái)我退出登錄了
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 {
//未知狀態(tài)嗎按照錯(cuò)誤情況處理
fail(message, DioError());
}
}
}
} else {
//返回?cái)?shù)據(jù)不是Map<String,dynamic>類型的,我們不統(tǒng)一處理,但是也按照成功的情況處理
// succ(Map(), response);
fail(netWrongMsg, DioError());
}
} else {
//此次網(wǎng)絡(luò)請(qǐng)求不通
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("數(shù)組長(zhǎng)度"+contextList.length.toString());
// contextList.forEach((c){
// print("數(shù)組元素=="+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);
});
}
}
}
關(guān)聯(lián)實(shí)體類文件
創(chuàng)建model
import 'package:json_annotation/json_annotation.dart';
part 'messageItemModel.g.dart';
@JsonSerializable()
class MessageItemModel{
String id = "";//這條消息的id
String toUserid = "";//這條消息是針對(duì)誰(shuí)的用戶id
String from = ""; //這條消息是誰(shuí)發(fā)起的用戶id
String infoDesc = "";//描述信息
String createBy = "";//創(chuàng)建人
String createDate = "";//創(chuàng)建時(shí)間
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);
});
此時(shí)下面代碼報(bào)錯(cuò),沒(méi)關(guān)系,先這樣寫(xiě)
part 'messageItemModel.g.dart';
在終端的項(xiàng)目根目錄執(zhí)行
flutter packages pub run build_runner build
此時(shí)生成了一個(gè)messageItemModel.g.dart文件,報(bào)錯(cuò)解決了,這個(gè)類里邊的代碼是自動(dòng)生成的,不要手動(dòng)修改,否則運(yùn)行錯(cuò)誤
// 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]