如果你目前正在使用 flutter 作为你的开发语言,那么你一定会碰到我取的这个标题所述的问题.
问题
为什么呢,因为 flutter 不支持反射,甚至禁用引入dart反射的这个库,所以我们需要生成具体的类的 fromJson 方法,对每一个字段进行decode 解析取值.
![](https://img.haomeiwen.com/i2217917/7ed9becf0d9eb73b.png)
也是因为反射,你在编写通用解析类的时候,无法动态生成类,无法获取类的属性,方法等等,无法生成类似 iOS 那种,硬编码调用方法的实现
举个例子原生端与flutter 端交互通信的问题
iOS 中,我们可以硬编码 call.method 的方法字符串,生成方法调用,从而省去字符串等式判断.
![](https://img.haomeiwen.com/i2217917/54c95e41007eb344.png)
![](https://img.haomeiwen.com/i2217917/4712c6c731956e7c.png)
![](https://img.haomeiwen.com/i2217917/5a5d03913a4fc70f.png)
而在 dart 中,我们只能添加字符串等于判断来调用其方法,相当于在 MethodCallHandler中要一一注册dart 中调用的方法,过程就多了一步.
![](https://img.haomeiwen.com/i2217917/be7d153e38f0cdf8.png)
正文
然后回到本文来,你可能用到过FlutterJsonBeanFactory,这是 Android Studio 的一个插件,用于生成 json to model 的文件
![](https://img.haomeiwen.com/i2217917/d5d2ded0a6d0e371.png)
他会主动帮你生成 fromJson 和 toJson 方法,并且用泛型类去解析,具体为
// 传入一个泛型,判断数组还是json 对象,进行具体的类判断解析
static M? fromJsonAsT<M>(dynamic json) {
if (json == null) {
return null;
}
if (json is List) {
return _getListChildType<M>(json);
} else {
return _fromJsonSingle<M>(json as Map<String, dynamic>);
}
}
static M? _fromJsonSingle<M>(Map<String, dynamic> json) {
final String type = M.toString();
if (type == (ListModel).toString()) {
return ListModel.fromJson(json) as M;
}
if (type == (Post).toString()) {
return Post.fromJson(json) as M;
}
if (type == (GiftList).toString()) {
return GiftList.fromJson(json) as M;
}
if (type == (Location).toString()) {
return Location.fromJson(json) as M;
}
if (type == (NewGiftBag).toString()) {
return NewGiftBag.fromJson(json) as M;
}
if (type == (PropList).toString()) {
return PropList.fromJson(json) as M;
}
if (type == (Stat).toString()) {
return Stat.fromJson(json) as M;
}
if (type == (TreasureResource).toString()) {
return TreasureResource.fromJson(json) as M;
}
if (type == (UserEntity).toString()) {
return UserEntity.fromJson(json) as M;
}
if (type == (APIResponse).toString()) {
return APIResponse.fromJson(json) as M;
}
print("$type not found");
return null;
}
更详细的我就不贴了,如果你使用了之后,你就会发现,他有一个问题,你不能继续传入泛型类的类型,
比如我这里最后要讲解的 Model类型
class ListModel<T> {
bool? hasMore;
int? pageSize;
int? pageNumber;
bool? empty;
int? total;
int? totalPage;
List<T>? list;
}
![](https://img.haomeiwen.com/i2217917/00fa4ef8b32bbb7b.png)
这种 model 是我的业务需要,相当于每个列表的返回数据类型都是这种类型,我即需要 List<T>数据,又需要 hasMore 这种后端返回帮我判断是否能进行上拉加载的字段,所以我必须要一个泛型类去解析.
接下来就是具体的代码实现
// 告诉 jsonConvert不解析该字段
@JSONField(name: "list", deserialize: false)
List<T>? list;
factory ListModel.fromJson(Map<String, dynamic> json) {
final ListModel<T> listModel = ListModel<T>();
final bool? hasMore = jsonConvert.convert<bool>(json['hasMore']);
if (hasMore != null) {
listModel.hasMore = hasMore;
}
final int? pageSize = jsonConvert.convert<int>(json['pageSize']);
if (pageSize != null) {
listModel.pageSize = pageSize;
}
final int? pageNumber = jsonConvert.convert<int>(json['pageNumber']);
if (pageNumber != null) {
listModel.pageNumber = pageNumber;
}
final bool? empty = jsonConvert.convert<bool>(json['empty']);
if (empty != null) {
listModel.empty = empty;
}
final int? total = jsonConvert.convert<int>(json['total']);
if (total != null) {
listModel.total = total;
}
final int? totalPage = jsonConvert.convert<int>(json['totalPage']);
if (totalPage != null) {
listModel.totalPage = totalPage;
}
final List<dynamic>? list =
jsonConvert.convert<List<dynamic>>(json['list']);
if (list != null) {
listModel.list = list.compactMap((element) {
if (element == null) {
return null;
}
final String type = T.toString();
if (type == (double).toString() ||
type == (int).toString() ||
type == (String).toString()) {
return element as T;
} else {
return JsonConvert.fromJsonAsT<T>(element);
}
});
}
return listModel;
}
这里的逻辑还是比较简单的,new 出一个泛型类
final ListModel<T> listModel = ListModel<T>();
然后单字段解析,最后对与泛型类
final List<dynamic>? list =
jsonConvert.convert<List<dynamic>>(json['list']);
if (list != null) {
listModel.list = list.compactMap((element) {
if (element == null) {
return null;
}
final String type = T.toString();
if (type == (double).toString() ||
type == (int).toString() ||
type == (String).toString()) {
return element as T;
} else {
return JsonConvert.fromJsonAsT<T>(element);
}
});
}
注意要先对其解析普通类型,因为 jsonConvert 生成的方法中不支持解析基本类型
![](https://img.haomeiwen.com/i2217917/c4676a3e4c7d6d4c.png)
compactMap 是我封装的去空 map 方法
List<T> compactMap<T>(T? toElement(E element)) {
List<T> temp = [];
for (var item in this) {
var toT = toElement(item);
if (toT != null) {
temp.add(toT);
}
}
return temp;
}
这样,你就可以直接支持一个 ListModel 泛型类解析了
另一个简单方法
但是,前面折腾了那么多,绕来绕去,云里雾里的,如果你不喜欢在 fromJson 中处理的话,实际上是有一个稍微有一点点麻烦(多写一行)但是又能够直接实现的方法.
![](https://img.haomeiwen.com/i2217917/80c9f110eaa0482b.png)
因为 jsonConvert 不支持数组泛型但是支持确定的数组类型解析,不过我个人喜欢在 fromJson 内直接处理掉这个逻辑,况且目前的 JsonConvert(4.2.8)并不支持基础类型的解析,我所使用ListModel有时候还是需要解析字符串数组等等的业务的,所以只能我自己添加基础类型解析的逻辑.我也与
FlutterJsonBeanFactory
作者提过,作者也说明会考虑在未来版本加入基础类型解析的.
我目前的使用习惯是,使用 vscode 中的Json to Dart Model生成model 和 json 解析方法,用buildrunner
监听文件改动,实时映射字段,手动添加 model 判断到 jsonconvert 值判断生成(这一步,大家可以随便找个空项目,用Android Studio 的FlutterJsonBeanFactory去生成 json_convert 文件的类型判断,复制过来即可.
就酱,下次再聊O(∩_∩)O~
网友评论