提前声明:本人一个被毕设折磨的学生,也是初学flutter,并不确定对于解析json这种功能有没有更简洁、更优雅的实现方式,但是我的这种方式确实能用,但也只能说是functional。😅
需求是这样的,后端定义了Result类对象作为统一返回的结果,
但是data部分的内容是不固定的,可能是分页对象,可能是数组,可能是某一个类对象,所以接收到的json就有三种形式,我想要的就是提取出data并解析成指定的类型。可惜最终并没有实现一个类就能统一处理三种返回类型,而是针对三种类型写了三个类进行解析处理。先从最简单的对象解析开始:
(1)对象
step1:先生成对象的实体类,我用的是quicktype:https://app.quicktype.io/
把json复制到左边,右边就是实体类:
然后,新建一个文件名为ResultObj.dart , 意为解析对象专用的类。
class ResultObj<T> {
String? msg;
int? code;
T? data;
ResultObj({
this.msg,
this.code,
this.data,
});
ResultObj.fromJson(Map<String, dynamic> json ,T Function(dynamic json) fromJsonT) {
// _$ResultObjFromJson(json, data);
msg=json['msg'];
code = json['code'];
data = fromJsonT(json['data'] as Map<String,dynamic>);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['code'] = this.code;
data['msg'] = this.msg;
data['data'] = this.data;
return data;
}
}
其中的T Function(dynamic json) fromJsonT 就是目标实体类的fromJson方法(此例中就是NewsType中的fromJson方法)
直接看看具体怎么使用就懂了,注意下面代码中,fromJson接收两个参数:
第一个是 response.data 变量,也就是就是网络请求后得到的Map<String, dynamic>类型的对象;
第二个参数是一个函数,就是告诉ResultObj用NewsType类中的fromJson方法进行处理。json就是一个形式变量,叫什么无所谓。
另外,注意ResultObj中定义了泛型T,但是具体用的时候填不填泛型无所谓,因为已经指明了是NewsType.fromJson(json)
使用方法:
var resultObj = ResultObj.fromJson(response.data, (json) => NewsType.fromJson(json));
NewsType newsType = resultObj.data;
(2)数组
处理数组其实就是在上面解析对象的基础上加了一个遍历,即:对数组中的每一个对象都调用一下传入的fromJsonT方法。
假设收到的json如下:
对应的用于解析数组的类,命名为ResultList:
class ResultList<T> {
String? msg;
int? code;
List<T>? data;
ResultList({
this.msg,
this.code,
this.data,
});
ResultList.fromJson(Map<String, dynamic> json,T Function(dynamic json) fromJsonT) {
msg=json['msg'];
code=json['code'];
data=(json['data'] as List<dynamic>).map((e) => fromJsonT(e)).toList();
}
}
重点就是其中的map((e) => fromJsonT(e)).toList();遍历了数组,把每个元素都用fromJsonT变成了NewsType对象。
使用上还是一样的:
var resultList = ResultList.fromJson(response.data, (json) => NewsType.fromJson(json));
List<NewsType> list = resultList.data!;
(3)分页对象
假设json长这样:
目标是提取出分页对象result,
通过result.msg即可获取到 “success”;
通过result.data.totalCount就可以知道总条目数 13;
通过result.data.list就可以获得 List< NewsType> 对象…
对应的解析用的类命名为ResultPage.dart:
class ResultPage<T> {
String? msg;
int? code;
Data<T>? data;
ResultPage({
this.msg,
this.code,
this.data,
});
ResultPage.fromJson(Map<String, dynamic> json,T Function(dynamic json) fromJsonT) {
msg=json['msg'];
code=json['code'];
data=Data.fromJson(json['data'], (json) => fromJsonT(json));
}
// Map<String, dynamic> toJson() => _$ResultPageToJson(this);
}
()
class Data<T> {
int? totalCount;
int? pageSize;
int? totalPage;
int? currentPage;
List<T>? list;
Data({
this.totalCount,
this.pageSize,
this.totalPage,
this.currentPage,
this.list,
});
Data.fromJson(Map<String, dynamic> json,T Function(dynamic json) fromJsonT) {
totalCount=json['totalCount'];
pageSize=json['pageSize'];
totalPage=json['totalPage'];
currentPage=json['currentPage'];
list=(json['list'] as List<dynamic>).map((e) => fromJsonT(e)).toList();
}
// Map<String, dynamic> toJson() => _$DataToJson(this);
}
这个稍微复杂点,因为data里套了一个page对象,page对象里套了个数组,但本质上就是上面两种情况的组合。泛型T从ResultPage传给了Data类。
实际使用:
ResultPage<News> result = ResultPage<News>.fromJson(response.data, (json) => News.fromJson(json));
var list = result.data!.list as List<News>
其实写完了再来看,好像也没有很复杂的样子。。。。😅