在flutter中進(jìn)行網(wǎng)絡(luò)請(qǐng)求有多種方式颖御,這里我使用的是dio扎阶。dio這個(gè)庫(kù)被封裝的很好躲胳,使用起來(lái)也很簡(jiǎn)單蒜鸡,但為了更方便我還是自己在做了簡(jiǎn)單的封裝胯努。整體代碼如下
class HttpRequestManager{
factory HttpRequestManager() =>getInstance();
static HttpRequestManager get instance =>getInstance();
static HttpRequestManager _instance;
Dio dio;
static CancelToken cancelToken;
String baseUrl="http://cardapi.mimiplay.cn/cardtest-api/";
String baseTestUrl="http://cardapi.mimiplay.cn/cardtest-api/";
HttpRequestManager._init(){
dio=new Dio();
BaseOptions options=BaseOptions(
baseUrl:GlobalData.isProduct? baseUrl:baseTestUrl,
connectTimeout: 20000,
receiveTimeout: 20000,
headers: {
"content-type": "application/json;charset=UTF-8"
},
contentType: Headers.jsonContentType,//請(qǐng)求類型
responseType: ResponseType.json,//接收類型
);
dio.options=options;
cancelToken=new CancelToken();
dio.interceptors.add(InterceptorsWrapper(//攔截器
onRequest: (RequestOptions options){
LogOut.I("請(qǐng)求地址: ${options.uri}");
LogOut.I("請(qǐng)求參數(shù): ${options.data}");
},
onResponse: (Response e){
// if (e.statusCode==200) {
// Map map=json.decode(e.data);
// BaseResult<T> data=BaseResult.fromJson(map);
// }
LogOut.I("服務(wù)器返回?cái)?shù)據(jù)----- ${e.toString()}");
}
));
}
static HttpRequestManager getInstance(){
if (_instance==null) {
_instance=new HttpRequestManager._init();
}
return _instance;
}
}
代碼也很簡(jiǎn)單牢裳,就是在單例類里對(duì)dio進(jìn)行一些設(shè)置,比如請(qǐng)求超時(shí)叶沛,請(qǐng)求頭蒲讯,返回類型等。然后也可以為其設(shè)置攔截灰署,攔截有三個(gè)方法分別是
onrequest:可以在此方法內(nèi)設(shè)置請(qǐng)求前的操作判帮,比如設(shè)置token等,我這里只是打印了請(qǐng)求地址和參數(shù)
onResponse:此處攔截工作在數(shù)據(jù)返回之后溉箕,可以在方法內(nèi)對(duì)dio請(qǐng)求的數(shù)據(jù)做二次封裝或者轉(zhuǎn)實(shí)體類等相關(guān)操作
onError:處理錯(cuò)誤
做完了對(duì)dio的基本封裝晦墙,下面就看下怎么使用其做網(wǎng)絡(luò)請(qǐng)求,并對(duì)數(shù)據(jù)進(jìn)行網(wǎng)絡(luò)解析约巷。具體代碼如下
typedef CallBackSuccess =Function(BaseResult result);//設(shè)置請(qǐng)求成功方法
typedef CallBackFail =Function(String message);//設(shè)置請(qǐng)求失敗方法
class HttpRequest{
static void postRequest(String url,{Map<String, dynamic> data,CancelToken cancelToken,Options options,CallBackSuccess success,CallBackFail fail}) async{
try {
options=options??Options(method: "POST");//默認(rèn)請(qǐng)求方法為post
Response response= await HttpRequestManager.instance.dio.request
(url,data:data,cancelToken:cancelToken,options: options);
if (response.statusCode==200) {
Map<String, dynamic> map=json.decode(response.toString());//請(qǐng)求成功將數(shù)據(jù)轉(zhuǎn)化成map
LogOut.I("data類型 ${map["data"].runtimeType}");//得到map里data的數(shù)據(jù)類型偎痛,方便接下來(lái)根據(jù)數(shù)據(jù)類型做解析
BaseResult result;//數(shù)據(jù)基類
if (map["data"] == null) {//data為null
result=BaseResult.fromNoData(map);
}else if (map["data"] is Map) {//data為map類型
result=BaseResult.fromJson(map);
}else if(map["data"] is List){//data為list類型
LogOut.I("list類型");
result=BaseResult.fromJsonList(map);
}else if(map["data"] is String){//data為字符串
result=BaseResult.fromString(map);
}
if(result.code=="900002"){
//todo 登錄失效處理
Fluttertoast.showToast(msg: result.message);
SPUtil util=await SPUtil.getInstances();
await util.setString("userId", "");
await util.setString("tokenId", "");
await util.setString("phone", "");
LogOut.I("登錄失效");
fail(result.message);
MyRouters.navigatorKey.currentState.push(MaterialPageRoute(builder: (context){
return new LoginPage();//登陸失效返回登錄頁(yè)
},));
}else{
if (success!=null) {
success(result);
}
}
}else{
if (fail!=null) {
fail(response.statusMessage+"錯(cuò)誤地址:$url");
}else{
Fluttertoast.showToast(msg: response.statusMessage);
}
}
} catch (e) {
print(e);
if (fail!=null) {
fail(e.toString()+"錯(cuò)誤地址:$url");
}
// callBack.fail(e.toString()+"錯(cuò)誤地址:$url");
}
}
}
在上面的代碼中,網(wǎng)絡(luò)請(qǐng)求方法默認(rèn)為post独郎,同時(shí)也做了數(shù)據(jù)解析踩麦。在flutter中數(shù)據(jù)解析不想Android那樣方便,我這里是對(duì)其進(jìn)行了分類型解析氓癌,這樣不管后臺(tái)返回的data為何種類型都有對(duì)應(yīng)的解析方式谓谦。解析成功后就是看自己的需求做操作了,我在這里做了登錄失效和請(qǐng)求成功的處理贪婉。成功時(shí)反粥,將baseresult傳入success方法里。至于baseresult是怎么分類型進(jìn)行解析的疲迂,我這里借助了FlutterJsonBeanFactory這個(gè)插件實(shí)現(xiàn)的才顿。下面看baseresult的具體代碼
class BaseResult<T>{
String code;
String message;
List<dynamic> listResult;
Map<String, dynamic> result;
String data;
BaseResult({this.code, this.message, this.listResult,this.result,this.data});
factory BaseResult.fromJsonList(Map<String, dynamic> json) {//data為list
return BaseResult(
code:json['code'],
message: json['message'],
listResult: json['data'],
);
}
factory BaseResult.fromNoData(Map<String, dynamic> json) {//data為空
return BaseResult(
code:json['code'],
message: json['message'],
);
}
factory BaseResult.fromJson(Map<String, dynamic> json) {//data為map
return BaseResult(
code:json['code'],
message: json['message'],
result: json['data'],
);
}
factory BaseResult.fromString(Map<String, dynamic> json) {//data為lString
return BaseResult(
code:json['code'],
message: json['message'],
data: json['data'],
);
}
List<T> getListData<T>(){//data為list,得到data
List<T> list=new List<T>();
if (listResult!=null) {
listResult.forEach((value) {
list.add(JsonConvert.fromJsonAsT<T>(value));//插件方法
});
}
return list;
}
T getMapData<T>(){//data為map尤蒿,得到data
LogOut.I("result $result");
return JsonConvert.fromJsonAsT<T>(result);//插件方法
}
String getData(){//data為string郑气,得到data
return data;
}
@override
String toString() {
return 'BaseResult{code: $code, message: $message, listResult: $listResult, result: $result, data: $data}';
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['code'] = this.code;
data['message'] = this.message;
if (this.result != null) {
data['data'] = this.result;
}else if(this.listResult != null){
data['data'] = this.listResult;
}else if(this.data!=null){
data['data'] = this.data;
}
return data;
}
}
上面網(wǎng)絡(luò)封裝和數(shù)據(jù)解析都已經(jīng)準(zhǔn)備好了,接下來(lái)就是調(diào)用的問(wèn)題了腰池,我這里做了一個(gè)類專門(mén)放各個(gè)接口請(qǐng)求尾组。具體代碼如下
class RequestUtil{
factory RequestUtil() =>getInstances();
static RequestUtil get requestUtil =>getInstances();
RequestUtil._init();
static RequestUtil _requestUtil;
static RequestUtil getInstances(){
if (_requestUtil==null) {
_requestUtil=new RequestUtil._init();
}
return _requestUtil;
}
Future<Map<String, dynamic>> _setBaseMap() async{//固定參數(shù)
LoginManager loginManager=LoginManager.getInstances();
LoginInfo info=await loginManager.getLogin();
String userId=info.userId;
String tokenId=info.tokenId;
Map<String, dynamic> map={
"userId":userId,
"tokenId":tokenId,
"clientVersion":clientVersion,
"clientType":clientType
};
return map;
}
///消息公告
getMessage(Map<String, dynamic> data,{success(BaseResult result),fail(message)}) async{
String url="notice/find/message";
Map<String, dynamic> map=await _setBaseMap();
map.addAll(data);
HttpRequest.postRequest(url,data: map,success:success,fail: fail);
}
///得到用戶信息
getUserInfo({success(BaseResult result),fail(message)}) async{
String url="account/userAccount/108/myAccountInfo";
Map<String, dynamic> map=await _setBaseMap();
HttpRequest.postRequest(url,data: map,success:success,fail: fail);
}
///登錄
doLogin(Map<String, dynamic> data,{success(BaseResult result),fail(message)}) async{
String url="auth/login/normal";
Map<String, dynamic> map=await _setBaseMap();
map.addAll(data);
HttpRequest.postRequest(url,data: map,success:success,fail: fail);
}
}
然后就是調(diào)用了,這里展示data為map類型和list類型的調(diào)用示弓。首先是map類型
RequestUtil.getInstances().doLogin({
"userMobileNo":userPhone,
"userPass":pass,
}, success: (result){//成功回調(diào)
LoginResult resultLogin=result.getMapData<LoginResult>();//通過(guò)baseresult的getMapData得到data
LogOut.I("${resultLogin.toString()}");
},fail: (message){
});
然后是list類型
void getMessage(){
RequestUtil.getInstances().getMessage({
"pageNum":1,
"pageSize":15
}, success: (result){
controller.refreshCompleted();
List<MessageResult> list=result.getListData<MessageResult>();//通過(guò)baseresult的getListData得到data
LogOut.I("解析后 $list");
},fail: (message){
});
}
到這里就將我自己做的flutter關(guān)于dio的網(wǎng)絡(luò)請(qǐng)求與數(shù)據(jù)解析說(shuō)完了讳侨,我個(gè)人覺(jué)得比較煩人的還是在數(shù)據(jù)解析這方面,關(guān)于flutter的數(shù)據(jù)解析還有多種方法奏属,比如使用json_serializable跨跨,我這里覺(jué)得這種方式比較舒服就是用了這種。