liuyulin
发布于 2024-02-29 / 108 阅读
0
0

Flutter中Json解析

json解析

两种json解析策略:

  • 手动序列化数据

  • 利用代码生成进行自动序列化数据

手动JSON解码是指在dart:convert中使用内置的json解码器,它包括将原始json字符串传递给jsonDecode()方法,然后在产生的Map<String,dynamic>计算结果中寻找你需要的值,它没有外部依赖或者特定的设置过程,有利于快速证明概念。

当项目变大时,手动编码就会变得难以管理并容易出错,需要使用代码生成的方法,可以通过外部的库生成编码模板,在一些初始化设置之后,可以运行文本监听程序,来从你的模型类生成代码,例如,json_serializablebuilt_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()方法


评论