有时,需要将来自API的JSON转换为对象,最好转换为不可变值。在Dart上可以实现,但需要为每个对象进行大量编码。幸运的是,有一个软件包可以帮助您完成所有这些工作,在本文中,我将向您介绍这种方法。
我们的目标:
1.序列化
final user = User.fromJson({"name": "Maks"});
final json = user.toJson();
2.用作值
final user1 = User.fromJson({"name": "Maks"});
final user2 = User((b) => b..name='Maks');
if (user1 == user2) print(' ');
3.不变性
user.name = 'Alex'; //
final newUser = user.rebuild((b) => b..name='Alex'); //
安装套件
在我们的Flutter项目中 打开pubspec.yaml文件,并将build_value包添加到依赖项:
...
built_value: ^7.1.0
并且还将build_value_generator和build_runner软件包添加到dev_dependencies中。这些软件包将帮助您生成所需的代码。
dev_dependencies:
...
build_runner: ^1.10.2
built_value_generator: ^7.1.0
保存pubspec.yaml文件并运行“ flutter pub get ”以获取所有必需的软件包。
创建built_value
让我们创建一个简单的类来查看一切如何工作。
创建一个新文件user.dart:
import 'package:built_value/built_value.dart';
part 'user.g.dart';
abstract class User implements Built<User, UserBuilder> {
String get name;
User._();
factory User([void Function(UserBuilder) updates]) = _$User;
}
因此,我们创建了一个简单的抽象User类,其中包含一个name字段,表明我们的类是user.g.dart的一部分,并且其中的主要实现包括UserBuilder。要自动创建此文件,您需要在命令行上运行它:
flutter packages pub run build_runner watch
要么
flutter packages pub run build_runner build
我们从监视开始,以免每次类发生更改时都重新启动。
之后,我们看到出现了一个新的user.g.dart文件。您可以查看其中的内容,并了解通过自动执行此过程可以节省多少时间。当我们添加更多字段并进行序列化时,此文件将变得更大。
让我们检查一下我们得到了什么:
final user = User((b) => b..name = "Max");
print(user);
print(user == User((b) => b..name = "Max")); // true
print(user == User((b) => b..name = "Alex")); // false
可为空
在User类中 添加一个新的姓氏字段:
abstract class User implements Built<User, UserBuilder> {
String get name;
String get surname;
...
}
如果您这样尝试:
final user = User((b) => b..name = 'Max');
然后我们得到一个错误:
Tried to construct class "User" with null field "surname".
为了让姓可选,使用可为空:
@nullable
String get surname;
或您每次都需要姓:
final user = User((b) => b
..name = 'Max'
..surname = 'Madov');
print(user);
建筑收藏
让我们使用数组。BuiltList将帮助我们:
import 'package:built_collection/built_collection.dart';
...
abstract class User implements Built<User, UserBuilder> {
...
@nullable
BuiltList<String> get rights;
...
final user = User((b) => b
..name = 'Max'
..rights.addAll(['read', 'write']));
print(user);
枚举
有必要限制权限,以使其不使用除“读取”,“写入”和“删除”以外的任何其他值。为此,请创建一个名为right.dart的新文件,并创建一个新的EnumClass:
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
part 'right.g.dart';
class Right extends EnumClass {
static const Right read = _$read;
static const Right write = _$write;
static const Right delete = _$delete;
const Right._(String name) : super(name);
static BuiltSet<Right> get values => _$rightValues;
static Right valueOf(String name) => _$rightValueOf(name);
}
用户:
@nullable
BuiltList<Right> get rights;
现在,权限仅接受权限类型:
final user = User((b) => b
..name = 'Max'
..rights.addAll([Right.read, Right.write]));
print(user);
序列化
为了使这些对象可以轻松地转换为JSON并返回,我们需要在类中添加更多方法:
...
import 'package:built_value/serializer.dart';
import 'serializers.dart';
...
abstract class User implements Built<User, UserBuilder> {
...
Map<String, dynamic> toJson() => serializers.serializeWith(User.serializer, this);
static User fromJson(Map<String, dynamic> json) =>
serializers.deserializeWith(User.serializer, json);
static Serializer<User> get serializer => _$userSerializer;
}
原则上,这足以进行序列化:
static Serializer<User> get serializer => _$userSerializer;
但是为了方便起见,让我们添加toJson和fromJson方法。
我们还向Right类添加一行:
import 'package:built_value/serializer.dart';
,,,
class Right extends EnumClass {
...
static Serializer<Right> get serializer => _$rightSerializer;
}
然后,您需要创建另一个名为serializers.dart的文件:
import 'package:built_collection/built_collection.dart';
import 'package:built_value/serializer.dart';
import 'package:built_value/standard_json_plugin.dart';
import 'package:built_value_demo/right.dart';
import 'package:built_value_demo/user.dart';
part 'serializers.g.dart';
@SerializersFor([Right, User])
final Serializers serializers =
(_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();
每个新的Built类都需要添加到@SerializersFor([ ... ])中,以使序列化能够按预期工作。
现在我们可以检查我们得到了什么:
final user = User.fromJson({
"name": "Max",
"rights": ["read", "write"]
});
print(user);
print(user.toJson());
final user2 = User((b) => b
..name = 'Max'
..rights.addAll([Right.read, Right.write]));
print(user == user2); // true
让我们更改值:
final user3 = user.rebuild((b) => b
..surname = "Madov"
..rights.replace([Right.read]));
print(user3);
另外
结果,会有人说你仍然需要写很多东西。但是,如果您使用Visual Studio Code,建议您安装一个名为“内置价值片段”的片段,然后您可以自动生成所有这些片段。为此,请搜索市场或点击此链接。
安装后,在Dart文件中写入“ bv ”,您可以看到存在哪些选项。
如果您不希望Visual Studio Code显示生成的“ * .g.dart ”文件,则需要打开“设置”并查找“ Files:Exclude”,然后单击“ Add Pattern”并添加“** / *。g.dart ”。
下一步是什么?
乍一看,似乎不值得付出太多的努力,但是如果您有很多这样的课程,这将极大地促进并加快整个过程。
PS:如果您分享自己的方法,我会非常高兴和感激,与我所建议的方法相比,您发现这些方法更实用,更有效。
GitHub项目
软件包:
pub.dev/packages/built_value
pub.dev/packages/built_value_generator
pub.dev/packages/build_runner