Flutter json 2 model with Built Value
2021-04-06 05:27
标签:ignore 第三方 就会 关键字 说明 第一个 first fail with Flutter中json转换model, 除了手动转之外, 就是利用第三方库做一些代码生成. 本文介绍built_value的实际使用及问题处理. Flutter中json到model类型的转换可以有多种方式: 使用json_serializable可以看: 本篇文章主要介绍built value的使用. 实例: 用github api拿到的events: https://api.github.com/events?per_page=10 先写个测试, 明确一下我们想要的目标. 在 里面写main函数和两个测试: 这里面应该放json字符串的, 太长了我就省略了, 这样看比较清晰. 用 这个 添加依赖, 去package页面看添加什么版本: https://pub.dev/packages/built_value 在 然后点 这个是IntelliJ系IDE(包括Android Studio)的快捷设置, 目的是为了减少手动输入. (可选.) 打开 下面Abbreviation选一个适当的缩写, 比如 Applicable in Dart选: top-level. 建好之后以后就直接用啦. 输入刚才建立的live template的关键字 比如我们要建立的model类型是 在其中输入 包括一个私有构造和一个工厂方法. 此时会有一些红色的报错. 根据观察API: https://api.github.com/events 返回的json, 发现还应该有 然后在其中添加字段, 现在看起来是这样了: 很重要的一步, 就是在类前面添加上一句: 按照同样的方法把几个类都建好. 注意如果有列表字段, 要声明为 生成命令: 需要持续构建和可以用: 这样就不用每次改完代码都需要跑一次命令了. 我们这里用watch, 因为还没有改完. 新建文件 注意这里要加上 因为我们跑命令的时候用的是 在Event类中添加: import中除了model类还有: 此时其他几个model类也要添加 重新build生成代码, 报错消失. 现在可以运行测试: 来检验单个的Event model建立. 可能会遇到的失败情况: Event的API返回的是一个Event的数组: 这里有个issue就是关于这个问题, 里面的解决办法挺好: https://github.com/google/built_value.dart/issues/565 在 其中 反序列化 到这一步, 跑我们开头写的两个测试应该都绿了. 如果没绿见 上面给 我们测试中的: 也可以这样写: 这样不用给每一个类都写一个 可能会有的报错, 问题原因和解决方式. 比如这个样子: 这是因为 比如 添加上重新build生成代码即可. 比如: 此时, 先不要着急把字段标记为 查看了一下果然就是, 解决办法: 如果字段真的是有可能为null的情况, 那么加上 比如: 相关issue: https://github.com/dart-lang/convert/issues/10 解决的办法就是在测试的字符串声明前加一个 有个很棒的工具: https://charafau.github.io/json2builtvalue/ 生成的 哈哈, 看到这里是不是有种被骗了的感觉. 有了这个很棒的工具之后根本不用自己很小心地写一个一个model类了, 只需要写一个 然后把要反序列化的类加进来, 再跑命令行生成代码, 就可以了. 经历一下前面的手动过程可能理解得更好一些, 也知道各种问题的原因. Flutter json 2 model with Built Value 标签:ignore 第三方 就会 关键字 说明 第一个 first fail with 原文地址:https://www.cnblogs.com/mengdd/p/flutter-json-2-model-with-built-value.htmlFlutter json 2 model with Built Value
流行的库有: json_serializable和built_valueFlutter中的json转model方法
built value使用指南
如何转化成model对象呢?TDD
test
下建立一个文件, 比如叫json_test.dart
.void main() {
test("parse events list", () {
const jsonString = """replace with events list json string""";
expect(Event.fromEventsListJson(jsonString).first.id, "11732023561");
});
test("parse event", () {
const jsonString = """replace with event json string""";
expect(Event.fromJson(jsonString).id, "11732036753");
});
}
"""
之后可以支持多行. (IDE里面可以折叠的.)Event
类和方法我们都还没有写, 所以暂时报错.setup
pubspec.yaml
中添加:dependencies:
flutter:
sdk: flutter
# other dependencies here
built_value: ^7.0.9
built_collection: ^4.3.2
dev_dependencies:
flutter_test:
sdk: flutter
# other dev_dependencies here
build_runner: ^1.8.0
built_value_generator: ^7.0.9
Packages get
.Live Templates
Preferences
, 搜Live Templates
.
在Dart
的部分点+号新增一个Live Template.built
.
Template text贴入这段:abstract class $CLASS_NAME$ implements Built {
$CLASS_NAME$._();
factory $CLASS_NAME$([void Function($CLASS_NAME$Builder) updates]) = _$$$CLASS_NAME$;
}
建立models抽象类
built
, 就会出现要生成的代码, 其中写好自己的类名.Event
类.
新建event.dart
文件.built
按确认之后, 输入类名Event
, 就建好了:abstract class Event implements Built
这里import ‘package:built_value/built_value.dart‘
消除Built
类的报错.Actor
, Repo
, Payload
三个类.
也都按这个方法建立好.import 'package:built_value/built_value.dart';
// imports for models
part 'event.g.dart';
abstract class Event implements Built
part ‘event.g.dart‘;
.g.dart
是一个惯例, 表明这个文件是生成的代码. part
表示目前这个文件是另一个文件的一部分.BuiltList
类型.运行生成命令
flutter packages pub run build_runner build
flutter packages pub run build_runner watch
运行完成之后, 可以看到.g.dart
的文件们都生成了, 报错也消失了.写Serializers
serializers.dart
.import 'package:built_value/serializer.dart';
import 'package:built_value/standard_json_plugin.dart';
// imports for models
part 'serializers.g.dart';
@SerializersFor(const [
Event,
Actor,
Repo,
Payload,
])
final Serializers serializers =
(_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();
@SerializersFor
里面列出想要序列化的类.StandardJsonPlugin
, 因为built value的json格式不是标准的, 而是所有字段逗号分隔的.
用了StandardJsonPlugin
之后就转换成了标准的JSON格式.watch
, 所以保存修改后serializers.g.dart
文件此时自动生成了.添加model序列化和反序列化代码
static Serializer
import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import 'serializers.dart';
serializer
, 比如Actor
类中添加:static Serializer get serializer => _$actorSerializer;
test("parse event", () {
const jsonString = """replace with event json string""";
expect(Event.fromJson(jsonString).id, "11732036753");
});
@nullable
.@BuiltValueField
的wireName
标记.
详见后面的Troubleshooting
部分.如何反序列化顶层列表?
[]
. 这种怎么做呢?serializers.dart
中添加方法:T deserialize
BuiltList
需要import ‘package:built_collection/built_collection.dart‘;
.Event
数组的方法: static List
Troubleshooting
部分.泛型的fromJson方法.
serializers
中添加了两个方法. 其中第一个方法是一个泛型的fromJson
方法.expect(Event.fromJson(jsonString).id, "11732036753");
expect(deserialize
fromJson
方法了.Troubleshooting
报错1:
failed due to: Invalid argument(s): Unknown type on deserialization. Need either specifiedType or discriminator field.
Deserializing '[id, 11732036753, type, PushEvent, actor, {id: 54496419, login: supershell201...' to 'Event' failed due to: Invalid argument(s): Unknown type on deserialization. Need either specifiedType or discriminator field.
Event
中依赖的类(Actor
, Repo
, Payload
)没有添加serializer.Actor
中:static Serializer get serializer => _$actorSerializer;
报错2:
Tried to construct class "XXX" with null field
Deserializing '[id, 11732036753, type, PushEvent, actor, {id: 54496419, login: supershell201...' to 'Event' failed due to: Deserializing '[id, 54496419, login, supershell2019, display_login, supershell2019, gravatar...' to 'Actor' failed due to: Tried to construct class "Actor" with null field "displayLogin". This is forbidden; to allow it, mark "displayLogin" with @nullable.
@nullable
.
而是要看这个字段是否真的为null, 很有可能是因为字段名称和json中的key不匹配造成的, 比如json中是个蛇形命名. @BuiltValueField(wireName: 'display_login')
String get displayLogin;
@nullable
:
比如: @BuiltValueField(wireName: 'ref_type')
@nullable
String get refType;
报错3:
FormatException: Control character in string
FormatException: Control character in string (at line 25, character 129)
... replica::on_client_write(dsn::message_ex *request, bool ignore_throttling)
r
:const jsonString = r"""replace with events list json string""";
Model生成工具推荐
左边输入json字符串, 写好命名, 点击之后右边就会出现那些本来需要手动写的代码.Event
类是这样:library event;
import 'dart:convert';
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
part 'event.g.dart';
abstract class Event implements Built
serializers.dart
文件:part 'serializers.g.dart';
@SerializersFor(const [
Event,
Actor,
Repo,
Payload,
])
final Serializers serializers =
(_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();
T deserialize
以后使用直接用工具就方便多了.参考资料
文章标题:Flutter json 2 model with Built Value
文章链接:http://soscw.com/index.php/essay/72009.html