json解析
两种json解析策略:
手动序列化数据
利用代码生成进行自动序列化数据
手动JSON解码是指在dart:convert中使用内置的json解码器,它包括将原始json字符串传递给jsonDecode()方法,然后在产生的Map<String,dynamic>计算结果中寻找你需要的值,它没有外部依赖或者特定的设置过程,有利于快速证明概念。
当项目变大时,手动编码就会变得难以管理并容易出错,需要使用代码生成的方法,可以通过外部的库生成编码模板,在一些初始化设置之后,可以运行文本监听程序,来从你的模型类生成代码,例如,json_serializable 和 built_value 就是这类的库。这种方法适用于大型项目,不需要手动编写模板,并且一些试图去获取不存在的json字段笔误,会在编译阶段被发现,但是需要一些初始化设置,并且生成的源文件可能在项目导航栏中产生一些视觉上的混乱。
Flutter中是否有Jackson的等价物?
没有。
这类库运行时需要进行反射,这在Flutter中是被禁用的。运行时反射会影响Dart支持了很久的摇树优化,通过tree shaking,可以从你的发布版本中抖掉不需要使用的代码。由于反射会默认让所有的代码被隐式使用,让tree shaking变得困难,工具不知道哪一部分在运行时不会被用到,所以冗余的代码很难被清除。
使用dart:convert手动序列化
Flutter有一个内置的dart:convert库,这个库中包含了一个简单的json编解码器
内联序列化json数据
解码方法
String _jsonStr;
late Map<String, dynamic> _jsonMap;
void serializeJsonStringByJsonDecode(String jsonStr) {
_jsonMap = jsonDecode(_jsonStr);
}例子
JsonSerializeDemoWidget(
jsonStr: '''{"name": "jack", "age": 32}''',
),
Text('${_jsonMap['name']} is ${_jsonMap['age']} years old.')使用这种方法意味着,在运行时以前都不知道值的类型,使用这个方法会失去大部分静态类型语言的特性:类型安全、自动补全以及重要的编译时异常,代码很容易出错。
在模型类中序列化json
可以通过在类中实现.fromJson构造方法,用于从映射中构造一个新的User实例,用toJson()方法,将实例转换为一个映射。通过这种方法,就可以拥有类型安全,并且能够自动完成以及编译时异常检测,不会使程序在运行时崩溃。
class User{
final String name;
final int age;
User(this.name,this.age);
User.fromJson(Map<String, dynamic> jsonMap)
: name = jsonMap['name'],
age = jsonMap['age'];
Map<String, dynamic> toJson() => {
'name': name,
'age': age,
};
}例子
void serializeJsonStringByClass(){
user0 = User.fromJson(_jsonMap);
}
Text('${user0.name} is ${user0.age} years old.'),
Text(jsonEncode(user0))对User实例进行编码,将User对象传到jsonEncode()函数中,不需要调用toJson()方法,jsonEncode()会调用。
通过这种方法,被调用的代码根本不需要担心序列化JSON数据的问题,然而,这样每个json字符串都需要对应的model类进行解析。
使用代码生成库序列化json数据
以json_serializable为例
引用json_serializable
在pubspec.yaml文件中引入依赖
dependencies:
json_annotation: ^4.4.0
dev_dependencies:
build_runner: ^2.1.8
json_serializable: ^6.1.5创建实体类
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class User {
User(this.name, this.age);
String name;
int age;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}运行代码生成工具
创建好上面的类会有一些爆红,这是很正常的,因为还未生成相关的代码,运行代码生成器之后这些爆红就会消失。
一次性代码生成
在项目根目录中运行flutter pub run build_runner build --delete-conflicting-outputs,这会遍历项目源文件,选择相关的文件,为它们生成必须的序列化数据代码
持续生成代码
运行flutter pub run build_runner watch启动监听,它会监听我们项目中文件的变化,并在需要的时候构建必要的文件。
使用json_serializable
和使用模型类一样,可以直接调用.fromJson()方法和jsonEncode()方法