序列化为JSON和不可变对象。关于Flutter的built_value程序包





有时,需要将来自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_generatorbuild_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;


但是为了方便起见,让我们添加toJsonfromJson方法



我们还向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



All Articles