系列文章目录
Flutter开发-01-简单JSON数据和序列化在Flutter中的最佳实践
Flutter开发-02-复杂JSON数据和序列化在Flutter中的最佳实践
前言
上一篇文章记录了序列化解析复杂结构JSON数据的几个方法。其中使用泛型去解析的方法,大多情况会遇到两种带有数组列表类型的JSON数据结构,一个是
data字段直接返回数组List,另一种是data字段返回的是一个分页的Bean对象,这个Bean对象中会有一个类似datas的字段返回数组List; 上文有好几种解析这两种JSON数据的方法。
1、使用泛型基类BaseResponse去解析,整个序列化非相同部分字段;
var userListBean = UserList.fromJson(userListMap);
2、JSON格式为返回List,使用 BaseResponse<List<User>> 去解析数据,这种方法注意一定要使用 List<dynamic> 进行强转,否则会报类型错误:
// 列表转换时一定要加一下强转List<dynamic>,否则会报错:type 'List<dynamic>' is not a subtype of type 'List<User>'
BaseResponse<List<User>> userListMap2 = BaseResponse.fromJson(userListMap,
(json) => (json as List<dynamic>)
// .map((e) => User.fromJson(e as Map<String, dynamic>))
.map((e) => User.fromJson(e))
.toList());
var usersMap = userListMap2.data;
3、解析带有分页类型数组的JSON数据,一种方法是使用泛型创建BaseResponse基类+data字段对应的序列化Bean对象:
BaseResponse<UserPageBean> userListMap3 =
BaseResponse.fromJson(json2Map, (json) => UserPageBean.fromJson(json));
var datas = userListMap3.data?.datas;
4、解析带有分页类型数组的JSON数据,另一种方法是使用泛型创建BaseResponse基类+data字段对应的序列化泛型类对象BaseList:
BaseResponse<BaseList<User>> userListMap3 = BaseResponse.fromJson(json2Map,
(json) => BaseList.fromJson(json, (json) => User.fromJson(json)));
BaseList<User>? baseUsers = userListMap3.data;
// var datas = baseUsers?.datas;
List<User>? usersMap3 = baseUsers?.datas;
虽然一个 BaseResponse 解决了两种数据结构,但使用时的代码会有些复杂,很容易出错。可以对这三种类型的接口进行单独处理,简化操作。
一、封装基类BaseResponse
适用于 data 字段返回统一的数据结构(最为推荐吧),直接把 data 字段返回的JSON数据进行序列化操作;
核心代码:
import 'package:json_annotation/json_annotation.dart';
part 'base_response.g.dart';
/// 一个注释,用于代码生成器,使其知道该类需要生成JSON序列化逻辑
@JsonSerializable(genericArgumentFactories: true)
class BaseResponse<T> {
//消息(例如成功消息文字/错误消息文字)
String? message;
bool? success = false;
//自定义code(可根据内部定义方式)
int? code;
//接口返回的数据
T? data;
BaseResponse({
this.message,
this.success,
this.code,
this.data,
});
/// 从映射创建新BaseResponse实例所需的工厂构造函数。将映射传递给生成的' _BaseResponseFromJson() '构造函数。
/// 构造函数以源类命名,在本例中为BaseResponse。
factory BaseResponse.fromJson(
Map<String, dynamic> json, T Function(dynamic json) fromJsonT) =>
_$BaseResponseFromJson<T>(json, fromJsonT);
/// ' toJson '是类声明支持序列化为JSON的约定。该实现仅仅调用私有的、生成的助手方法' _BaseResponseToJson '。
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) =>
_$BaseResponseToJson<T>(this, toJsonT);
}
二、封装BaseListResponse基类
对于返回的JSON数据中 data 字段返回的是数组List的情形,可以直接使用泛型基类BaseListResponse去解析:
JOSN数据:
{
"code":0,
"message":"Success",
"data":[
{
"name":"Jerry",
"email":"Jerry@example.com"
},
{
"name":"Alex",
"email":"Alex@example.com"
},
{
"name":"Tom",
"email":"Tom@example.com"
},
{
"name":"Jack",
"email":"Jack@example.com"
},
{
"name":"Lucy",
"email":"Lucy@example.com"
}
]
}
核心代码:
import 'package:json_annotation/json_annotation.dart';
part 'base_list_response.g.dart';
@JsonSerializable(genericArgumentFactories: true)
class BaseListResponse<T> {
List<T> data;
int code;
String message;
BaseListResponse(this.data, this.code, this.message);
factory BaseListResponse.fromJson(
Map<String, dynamic> json, T Function(dynamic json) fromJsonT) =>
_$BaseListResponseFromJson<T>(json, fromJsonT);
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) =>
_$BaseListResponseToJson<T>(this, toJsonT);
}
数据解析代码:
Future decodeAssetJson() async {
// 解析本地数据-List数组
Map<String, dynamic> userListMap =
await loadJsonAssets("assets/user_list.json");
// 使用泛型基类BaseListResponse<T>去解析返回List数组类型的JOSN数据
BaseListResponse<User> result =
BaseListResponse.fromJson(userListMap, (json) => User.fromJson(json));
List<User> list = result.data;
if (kDebugMode) {
print('\n ===============BaseListResponse解析数组开始================== \n ');
print('result : $result');
print('result : ${result.toString()}');
if (list.isNotEmpty) {
for (int i = 0; i < (list.length); i++) {
print('result list $i : ${list[i].name}');
print('result list $i : ${list[i].email}');
}
}
print('\n ===============BaseListResponse解析数组结束================== \n ');
}
}
输出日志:
result : Instance of 'BaseListResponse<User>'
result toString : Instance of 'BaseListResponse<User>'
result list 0 : Jerry
result list 0 : Jerry@example.com
...
三、封装BaseListResponse基类
对于返回的JSON数据中 data 字段返回的是数组List的情形,可以直接使用泛型基类BaseListResponse去解析:
JSON数据:
{
"data":{
"curPage":1,
"datas":[
{
"name":"肖战",
"email":"肖战@example.com"
},
{
"name":"丁程鑫",
"email":"丁程鑫@example.com"
},
{
"name":"贺峻霖",
"email":"贺峻霖@example.com"
},
{
"name":"李天泽",
"email":"李天泽@example.com"
},
{
"name":"刘耀文",
"email":"刘耀文@example.com"
},
{
"name":"成毅",
"email":"成毅@example.com"
}
],
"offset":0,
"over":false,
"pageCount":3,
"size":20,
"total":46
},
"code":0,
"message":"Success get"
}
数据解析代码:
Future decodeAssetJson() async {
// 解析本地数据-List数组
Map<String, dynamic> json2Map =
await loadJsonAssets("assets/user_list2.json");
// 使用泛型基类BasePageListResponse<T> + PageList<T>去解析返回分页List数组类型的JOSN数据
BasePageListResponse<User> result2 =
BasePageListResponse.fromJson(json2Map, (json) => User.fromJson(json));
var data = result2.data;
// PageList<User> data = result2.data;
var list2 = data.datas;
// List<User> list2 = data.datas;
if (kDebugMode) {
print('\n ===============BasePageListResponse解析数组开始================== \n ');
print('result : $result2');
print('result toString : ${result2.toString()}');
print('result code : ${result2.code}');
print('result message : ${result2.message}');
print('result data : ${result2.data}');
print('result data curPage: ${result2.data.curPage}');
print('result datas : ${result2.data.datas}');
print('result datas jsonEncode: ${jsonEncode(result2.data.datas)}');
if (list2.isNotEmpty) {
for (int i = 0; i < (list2.length); i++) {
print('result list $i : ${list2[i].name}');
print('result list $i : ${list2[i].email}');
}
}
print('\n ===============BasePageListResponse解析数组结束================== \n ');
}
}
输出日志:
result : Instance of 'BasePageListResponse<User>'
result toString : Instance of 'BasePageListResponse<User>'
result code : 0
result message : Success get
result data : Instance of 'PageList<User>'
result datas : [Instance of 'User', Instance of 'User', Instance of 'User', Instance of 'User', Instance of 'User', Instance of 'User']
result data curPage: 10
result datas jsonEncode: [{"name":"肖战","email":"肖战@example.com"},{"name":"丁程鑫","email":"丁程鑫@example.com"},{"name":"贺峻霖","email":"贺峻霖@example.com"},{"name":"李天泽","email":"李天泽@example.com"},{"name":"刘耀文","email":"刘耀文@example.com"},{"name":"成毅","email":"成毅@example.com"}]
result list 0 : 肖战
result list 0 : 肖战@example.com
...
总结
提示:这里对文章进行总结:
以上两种JSON数据序列化后的数据解析代码就很统一了:
返回数组List的JSON解析:
// 使用泛型基类BaseListResponse<T>去解析返回List数组类型的JOSN数据
BaseListResponse<User> result =
BaseListResponse.fromJson(userListMap, (json) => User.fromJson(json));
List<User> list = result.data;
返回分页数组列表的JSON解析:
// 使用泛型基类BasePageListResponse<T> + PageList<T>去解析返回分页List数组类型的JOSN数据
BasePageListResponse<User> result2 =
BasePageListResponse.fromJson(json2Map, (json) => User.fromJson(json));
var data = result2.data;
// PageList<User> data = result2.data;
var list2 = data.datas;
// List<User> list2 = data.datas;
以上三种方法我觉得都很简洁,但是最好统一使用方法最好。即全部使用
BaseResponse<T>只对data返回的字段进行序列化操作,然后进行数据解析; 或者 1、使用BaseResponse<T>解析一般结构的JSON数据,使用BaseListResponse<T>去解析返回数组List的JSON数据,只去序列化数组List中的Bean对象(比如本例中的User); 2、使用BasePageList<T>+PageList<T>去解析返回 "分页" List的JSON数据,也是只去序列化数组List中的Bean对象(比如本例中的User);