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

1 回复

更多关于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_$UserToJsoneasy_serialization插件在编译时自动生成的函数。

3. 序列化和反序列化

现在你可以使用生成的fromJsontoJson方法来进行序列化和反序列化了。

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对象之间的转换过程,使得数据处理更加高效和简单。

回到顶部