Flutter数据序列化插件easy_serialization的使用
Flutter数据序列化插件easy_serialization的使用
描述
这个包帮助你系统地处理序列化问题,尤其在序列化列表和抽象类型时提供了很大的帮助。
使用
第一步:定义你的类型
/// 代表来自Flutter SDK的[Offset]类型。
class Offset {
final double dx, dy;
const Offset(this.dx, this.dy);
}
enum ShapeFillType {
solid,
outlined,
}
abstract class Shape with SerializableMixin {
Offset offset = const Offset(0, 0);
ShapeFillType fill = ShapeFillType.solid;
Shape();
double area();
/// 如果这些对象是原语,则直接传递;否则使用[Prop]进行序列化。
@override
MarkupObj toMarkupObj() => {
"offset": Prop.valueToMarkup(offset),
"fill": Prop.valueToMarkup(fill),
};
/// 如果这些对象是原语,则直接传递;否则使用[Prop]进行序列化。
Shape.fromMarkup(MarkupObj markup)
: offset = Prop.valueFromMarkup(markup["offset"]),
fill = Prop.valueFromMarkup(markup["fill"]);
}
class Circle extends Shape {
double radius;
Circle(this.radius);
@override
double area() => 3.14 * radius * radius;
@override
MarkupObj toMarkupObj() => {
...super.toMarkupObj(),
"radius": radius,
};
Circle.fromMarkup(MarkupObj markup)
: radius = markup["radius"],
super.fromMarkup(markup);
}
class Rectangle extends Shape {
double height, width;
Rectangle(this.height, this.width);
@override
double area() => height * width;
@override
MarkupObj toMarkupObj() => {
...super.toMarkupObj(),
"height": height,
"width": width,
};
Rectangle.fromMarkup(MarkupObj markup)
: height = markup["height"],
width = markup["width"],
super.fromMarkup(markup);
}
class Square extends Rectangle {
Square(double sideLen) : super(sideLen, sideLen);
Square.fromMarkup(MarkupObj markup) : super.fromMarkup(markup);
}
第二步:注册这些类型
final customSerializableObjects = [
/// 如何配置一个不是你的类型(来自不同的库),或者只是你不想使用[SerializableMixin]的类型。
SerializationConfig<Offset>(
toMarkupObj: (obj) => {"dx": obj.dx, "dy": obj.dy},
fromMarkupObj: (markup) => Offset(markup["dx"], markup["dy"]),
),
/// 如何配置枚举类型。
ShapeFillType.values.config,
/// 如何配置你的类型。
/// [SerializationConfig.abstract]用于创建一个该抽象类型的列表。
SerializationConfig.abstract<Shape>(),
SerializationConfig.serializable<Circle>(Circle.fromMarkup),
SerializationConfig.serializable<Rectangle>(Rectangle.fromMarkup),
SerializationConfig.serializable<Square>(Square.fromMarkup),
];
void main() async {
// 在每个新的隔离区或服务中,你必须首先配置此列表。
Prop.registerSerializationConfigs(customSerializableObjects);
final circle = Circle(5.0)
..fill = ShapeFillType.solid
..offset = Offset(20, 20);
final rect = Rectangle(10, 10)
..fill = ShapeFillType.outlined
..offset = Offset(10, 10);
final square = Square(75);
final list = <List<Shape>>[
[circle],
[rect, square],
[]
];
/// [Prop.valueToMarkup] 和 [Prop.valueFromMarkup] 将静态地推断类型,
/// 但最好显式地传递类型,特别是对于[List]。
/// 注意这里你必须提供一个空列表实例。
///
/// 这个标记可以发送到任何隔离区,或者如果你想将其解析为JSON字符串,请使用json.encode和json.decode。
final msg = Prop.valueToMarkup<List<List<Shape>>>(list, emptyList: []);
Isolate.spawn(isolateMain, msg);
// 仅为了展示第二个隔离区中的打印结果。
await Future.delayed(const Duration(seconds: 2));
}
然后你可以直接在隔离区之间发送和接收标记,
或者如果你想将其作为JSON字符串发送,可以使用json.encode和json.decode。 以下是第二个隔离区:
/// 这可以是任何服务的入口点,例如[flutter_background_service]包,
/// 或者像[overlay_window]包这样的覆盖服务,
///
/// 或者甚至是一个客户端-服务器应用
/// (但在这种情况下,两者都必须一起编译在一起[在未来更新中这将变得更加清晰])。
void isolateMain(MarkupObj msg) {
// 在每个新的隔离区或服务中,你必须首先配置此列表。
Prop.registerSerializationConfigs(customSerializableObjects);
/// 注意这里你必须提供一个空列表实例。
/// 注意这里任何内部空列表都会被忽略。
final ml = Prop.valueFromMarkup<List<List<Shape>>>(
msg,
emptyList: [],
);
print(ml); // 发送的精确列表。
print(ml[0][0].offset.dx); // 20
print(ml.runtimeType); // List<List<Shape>>
print(ml[0].runtimeType); // List<Circle>
print(ml[1].runtimeType); // List<Rectangle>
}
工具
1. TypeProvider<OBJ>
混入类
TypeProvider<OBJ>
混入类允许你在任何时间动态地存储和使用泛型类型 [OBJ]。
class MyList<E> with TypeProvider<E> {
final List<E> list;
const MyList(this.list);
}
void main() {
final myList = const MyList<int>([5, 6]);
final dynamicList = myList as MyList;
dynamicList.provType(() => print(dynamicList.runtimeType)); // MyList<int>
}
2. TypeHash<OBJ>
类
TypeHash<OBJ>
类允许你获取每个已注册类型的唯一ID(某些情况下你必须注册所有类型)。
class Configration<E> with TypeHash<E> {
final E obj;
Configration(this.obj) {
ensureCalcTypeID();
}
}
void main() {
final config = Configration<int>(7);
print(config.typeID.hashCodes); // [List<int>]
}
3. withoutEmpties
方法
withoutEmpties
方法可以从提供的列表中移除任何空列表。
final list = [1, "A", [], [5, [6], []], [[[]]]];
print(list.withoutEmpties()); // [1, A, [5, [6]]]
4. withSpecificTypes
方法
withSpecificTypes
方法会将列表及其子列表转换为其最具体的已注册类型(某些情况下你必须注册所有类型)。
final list1 = <dynamic>[[1, 2], [1.1, 2.2]];
print(list1.runtimeType); // List<dynamic>
final list2 = list1.withSpecificTypes();
print(list2.runtimeType); // List<List<num>>
print(list2[0].runtimeType); // List<int>
print(list2[1].runtimeType); // List<double>
更多关于Flutter数据序列化插件easy_serialization的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据序列化插件easy_serialization的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用easy_serialization
插件进行数据序列化的代码案例。easy_serialization
是一个帮助Flutter开发者简化数据序列化和反序列化过程的插件。
1. 添加依赖
首先,你需要在pubspec.yaml
文件中添加easy_serialization
的依赖:
dependencies:
flutter:
sdk: flutter
easy_serialization: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来获取依赖。
2. 创建数据模型
接下来,你需要创建一个数据模型,并使用@Serializable
注解来标记它。以下是一个简单的示例:
import 'package:easy_serialization/easy_serialization.dart';
@Serializable()
class User {
String name;
int age;
User({required this.name, required this.age});
// 从JSON反序列化
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
// 序列化为JSON
Map<String, dynamic> toJson() => _$UserToJson(this);
}
注意,_$UserFromJson
和_$UserToJson
是easy_serialization
插件在编译时自动生成的函数。
3. 序列化和反序列化
现在你可以使用生成的fromJson
和toJson
方法来进行序列化和反序列化了。
void main() {
// 创建一个User对象
User user = User(name: 'Alice', age: 30);
// 将User对象序列化为JSON
Map<String, dynamic> userJson = user.toJson();
print('Serialized JSON: $userJson');
// 从JSON反序列化为User对象
User deserializedUser = User.fromJson(userJson);
print('Deserialized User: ${deserializedUser.name}, Age: ${deserializedUser.age}');
}
4. 在Flutter应用中使用
在Flutter应用中,你可能需要在按钮点击或数据获取后进行序列化和反序列化。以下是一个简单的Flutter界面示例:
import 'package:flutter/material.dart';
import 'package:easy_serialization/easy_serialization.dart';
@Serializable()
class User {
String name;
int age;
User({required this.name, required this.age});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: UserScreen(),
);
}
}
class UserScreen extends StatefulWidget {
@override
_UserScreenState createState() => _UserScreenState();
}
class _UserScreenState extends State<UserScreen> {
User? user;
final TextEditingController nameController = TextEditingController();
final TextEditingController ageController = TextEditingController();
void serializeUser() {
if (user != null) {
Map<String, dynamic> userJson = user!.toJson();
print('Serialized JSON: $userJson');
}
}
void deserializeUser(Map<String, dynamic> json) {
setState(() {
user = User.fromJson(json);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('User Serialization'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: nameController,
decoration: InputDecoration(labelText: 'Name'),
),
TextField(
controller: ageController,
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: 'Age'),
),
ElevatedButton(
onPressed: () {
setState(() {
user = User(name: nameController.text, age: int.parse(ageController.text));
});
serializeUser();
},
child: Text('Serialize'),
),
ElevatedButton(
onPressed: () {
Map<String, dynamic> userJson = {
'name': 'Bob',
'age': 25,
};
deserializeUser(userJson);
},
child: Text('Deserialize'),
),
if (user != null)
Text('User: ${user!.name}, Age: ${user!.age}'),
],
),
),
);
}
}
这个示例创建了一个简单的Flutter应用,允许用户输入名称和年龄,然后点击按钮进行序列化和反序列化。
总结
以上是使用easy_serialization
插件在Flutter项目中进行数据序列化和反序列化的代码案例。这个插件简化了JSON与Dart对象之间的转换过程,使得数据处理更加高效和简单。