没使用过json_serializable的,可以参考Flutter 中的JSON序列化
version
dependencies:
flutter:
sdk: flutter
# handling JSON
json_serializable: ^4.1.0
支持泛型化?
json_serializable 是支持泛型的(genericArgumentFactories设置为true),这通过文档可以看到
/// ```dart
/// @JsonSerializable(genericArgumentFactories: true)
/// class Response<T> {
/// int status;
/// T value;
/// }
/// ```
///
/// Looks like
///
/// ```dart
/// Response<T> _$ResponseFromJson<T>(
/// Map<String, dynamic> json,
/// T Function(Object json) fromJsonT,
/// ) {
/// return Response<T>()
/// ..status = json['status'] as int
/// ..value = fromJsonT(json['value']);
/// }
///
/// Map<String, dynamic> _$ResponseToJson<T>(
/// Response<T> instance,
/// Object Function(T value) toJsonT,
/// ) =>
/// <String, dynamic>{
/// 'status': instance.status,
/// 'value': toJsonT(instance.value),
/// };
实际使用
请求状态码
拿经常用的http请求后的状态数据举个例子:
{
"errno": 0,
"message": "请求成功",
"data": {
"title": "请问外环路怎么走?",
"scores_num": 9
}
}
创建RoadBean
import 'package:json_annotation/json_annotation.dart';
part 'road_bean.g.dart';
@JsonSerializable()
class RoadBean {
String title;
@JsonKey(name: 'scores_num')
int scoresNum;
RoadBean(this.title, this.scoresNum);
factory RoadBean.fromJson(Map<String, dynamic> json) =>
_$RoadBeanFromJson(json);
Map<String, dynamic> toJson() => _$RoadBeanToJson(this);
}
Terminal运行命令:
flutter pub run build_runner build
生成的代码在road_bean.g.dart文件中,如下:
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'road_bean.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
RoadBean _$RoadBeanFromJson(Map<String, dynamic> json) {
return RoadBean(
json['title'] as String,
json['scores_num'] as int,
);
}
Map<String, dynamic> _$RoadBeanToJson(RoadBean instance) => <String, dynamic>{
'title': instance.title,
'scores_num': instance.scoresNum,
};
创建BaseResult类,并使用泛型参数(T)
import 'package:json_annotation/json_annotation.dart';
part 'base_result.g.dart';
@JsonSerializable(genericArgumentFactories: true)
class BaseResult<T> {
int errno;
String message;
T data;
BaseResult(this.errno, this.message, this.data);
factory BaseResult.fromJson(
Map<String, dynamic> json,
T Function(dynamic json) fromJsonT,
) =>
_$BaseResultFromJson(json, fromJsonT);
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) =>
_$BaseResultToJson(this, toJsonT);
}
Note:方法fromJson中的参数T Function(dynamic json) fromJsonT 是一个数据类型为dynamic,参数名为json的函数
Terminal运行命令:
flutter pub run build_runner build
生成的代码在base_result.g.dart文件中,如下:
part of 'base_result.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
BaseResult<T> _$BaseResultFromJson<T>(
Map<String, dynamic> json,
T Function(Object? json) fromJsonT,
) {
return BaseResult<T>(
json['errno'] as int,
json['message'] as String,
fromJsonT(json['data']),
);
}
Map<String, dynamic> _$BaseResultToJson<T>(
BaseResult<T> instance,
Object? Function(T value) toJsonT,
) =>
<String, dynamic>{
'errno': instance.errno,
'message': instance.message,
'data': toJsonT(instance.data),
};
在生成的代码_$BaseResultFromJson中fromJsonT 的 参数为Object类型的
测试
String json =
"{\"errno\": 0,\"message\": \"请求成功\",\"data\": {\"title\": \"请问外环路怎么走?\",\"scores_num\": 9}}";
var jsonObject = jsonDecode(json);
BaseResult<RoadBean> baseResult =
BaseResult.fromJson(jsonObject, (json) => RoadBean.fromJson(json));
print("scoresNum == ${baseResult.data.scoresNum}");
输出:
I/flutter (26052): scoresNum == 9
Note
在BaseResult生成的代码_$BaseResultFromJson中fromJsonT 的 参数为Object类型的,
照此,BaseResult中的fromJson应该为这样的
factory BaseResult.fromJson(
Map<String, dynamic> json,
T Function(Object? json) fromJsonT,
) =>
_$BaseResultFromJson(json, fromJsonT);
改成这样以后,这句代码
BaseResult<RoadBean> baseResult =
BaseResult.fromJson(jsonObject, (json) => RoadBean.fromJson(json));
就会报错:: argument_type_not_assignable
The argument type 'Object?' can't be assigned to the parameter type
'Map<String, dynamic>'.
因为在RoadBean.fromJson中的参数是Map<String, dynamic>类型的,2者类型是不一致的。
这里提供2种解决方式:
1 as强转
BaseResult<RoadBean> baseResult = BaseResult.fromJson(
jsonObject, (json) => RoadBean.fromJson(json as Map<String, dynamic>));
不过这种得保证在实参的运行时类型将始终与形参的静态类型相同。并且冒着出错抛出异常的风险,那么你可以添加一个显式的类型转换
2 如上述把Object?替换为dynamic
factory BaseResult.fromJson(
Map<String, dynamic> json,
T Function(dynamic json) fromJsonT,
) =>
_$BaseResultFromJson(json, fromJsonT);