Flutter数据序列化插件carp_serializable的使用

发布于 1周前 作者 bupafengyu 来自 Flutter

Flutter数据序列化插件carp_serializable的使用

简介

carp_serializable 是一个基于 json_serializable 的 Dart 包,用于实现从 JSON 到对象的多态(polymorphic)序列化和反序列化。它通过在 JSON 中添加类型信息来支持继承类的序列化。在使用该插件之前,请确保你已经熟悉了 json_serializable 的基本用法。

入门

要在项目中使用 carp_serializable,你需要在 pubspec.yaml 文件中添加以下依赖:

dependencies:
  json_annotation: ^latest
  carp_serializable: ^latest

dev_dependencies:
  build_runner: any   # 用于生成 JSON 序列化代码
  json_serializable: any

使用方法

为了支持多态序列化,每个类需要满足以下条件:

  1. 继承 Serializable:所有需要序列化的类都必须继承自 Serializable
  2. 使用 @JsonSerializable 注解:为类添加 @JsonSerializable 注解。
  3. 实现三个 JSON 方法
    • Function get fromJsonFunction => ...:返回从 JSON 反序列化的函数。
    • factory ...fromJson(...):工厂构造函数,用于从 JSON 创建对象。
    • Map<String, dynamic> toJson() => ...:将对象转换为 JSON 的方法。
  4. 注册类到 FromJsonFactory:在应用程序启动时,将类注册到 FromJsonFactory 单例中。
  5. 生成序列化代码:使用 flutter pub run build_runner build --delete-conflicting-outputs 命令生成 fromJsontoJson 方法。

示例代码

以下是一个完整的示例,展示了如何使用 carp_serializable 进行多态序列化和反序列化。

import 'package:carp_serializable/carp_serializable.dart';
import 'package:json_annotation/json_annotation.dart';

// Auto generate json code (.g files) with:
//   dart run build_runner build --delete-conflicting-outputs
part 'example.g.dart';

/// 基础类 A
@JsonSerializable()
class A extends Serializable {
  int index;

  A([this.index = 0]) : super();

  @override
  Function get fromJsonFunction => _$AFromJson;

  factory A.fromJson(Map<String, dynamic> json) =>
      FromJsonFactory().fromJson<A>(json);

  @override
  Map<String, dynamic> toJson() => _$AToJson(this);
}

/// 继承自 A 的类 B
///
/// 该类展示了三个非默认行为:
///  * 可为空的字符串 [str] 不会包含在 JSON 中,因为 [includeIfNull] 设置为 false
///  * 拥有自定义的 [jsonType] 类型名称
///  * 在 [fromJson] 工厂方法中提供了 [notAvailable] 参数,指定如果未注册 fromJson 方法时的默认值
@JsonSerializable(includeIfNull: false)
class B extends A {
  String? str;

  B([super.index, this.str]) : super();

  @override
  String get jsonType => 'dk.carp.$runtimeType';

  @override
  Function get fromJsonFunction => _$BFromJson;
  factory B.fromJson(Map<String, dynamic> json) =>
      FromJsonFactory().fromJson<B>(json, notAvailable: B(-1));
  @override
  Map<String, dynamic> toJson() => _$BToJson(this);
}

/// 包含另一个可序列化类 B 的类 C
///
/// 注意 [explicitToJson] 必须设置为 true,以便通过 [toJson] 方法进行“深度”JSON 序列化
@JsonSerializable(explicitToJson: true)
class C extends A {
  B b;

  C(super.index, this.b) : super();

  @override
  Function get fromJsonFunction => _$CFromJson;
  factory C.fromJson(Map<String, dynamic> json) =>
      FromJsonFactory().fromJson<C>(json);
  @override
  Map<String, dynamic> toJson() => _$CToJson(this);
}

void main() {
  // 记得在 JSON Factory 中注册反序列化函数
  FromJsonFactory().register(A());
  FromJsonFactory().register(B());
  FromJsonFactory().register(C(0, B()));

  // 也可以使用不同的 jsonType 注册 B
  FromJsonFactory().register(B(1), type: 'B');

  A a = A(1);
  B b = B(2, 'abc');
  C c = C(3, b);

  print(toJsonString(a));  // 输出 A 的 JSON
  print(toJsonString(b));  // 输出 B 的 JSON
  print(toJsonString(c));  // 输出 C 的 JSON

  A newA = A.fromJson(a.toJson());
  B newB = B.fromJson(b.toJson());

  // 注意以下代码只有在 C 类注解中设置了 "explicitToJson" 为 true 时才有效
  // 这确保了 JSON 的“深度”转换
  C newC = C.fromJson(c.toJson());

  print(toJsonString(newA.toJson()));  // 输出反序列化后的 A 的 JSON
  print(toJsonString(newB.toJson()));  // 输出反序列化后的 B 的 JSON
  print(toJsonString(newC.toJson()));  // 输出反序列化后的 C 的 JSON
}

关键点解释

  1. 多态序列化:通过在 JSON 中添加 __type 字段,carp_serializable 支持多态类的序列化。例如,AB 类的 JSON 输出如下:

    {
      "__type": "A",
      "index": 1
    }
    
    {
      "__type": "B",
      "index": 2,
      "str": "abc"
    }
    
  2. 自定义类型名称:你可以通过重写 jsonType 属性来自定义 JSON 中的类型名称。例如,B 类可以使用 dk.carp.B 作为类型名称:

    {
      "__type": "dk.carp.B",
      "index": 2,
      "str": "abc"
    }
    
  3. 嵌套类C 类包含了一个 B 类实例。为了支持嵌套类的序列化,你需要在 @JsonSerializable 注解中设置 explicitToJson: true。这样可以确保 C 类的 toJson 方法能够正确地序列化其内部的 B 类实例。

    {
      "__type": "C",
      "index": 3,
      "b": {
        "__type": "dk.carp.B",
        "index": 2,
        "str": "abc"
      }
    }
    

更多关于Flutter数据序列化插件carp_serializable的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据序列化插件carp_serializable的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 carp_serializable 插件进行数据序列化的 Flutter 代码示例。carp_serializable 是一个用于 Flutter 和 Dart 的序列化库,特别适用于需要复杂对象序列化和反序列化的场景,比如科学研究数据收集应用。

首先,确保你已经在 pubspec.yaml 文件中添加了 carp_serializable 依赖:

dependencies:
  flutter:
    sdk: flutter
  carp_serializable: ^x.y.z  # 替换为最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来,我们创建一个简单的示例,展示如何使用 carp_serializable 插件。

步骤 1: 定义数据模型

首先,定义一个数据模型,并使用 @CarpSerializable() 注解标记它。

import 'package:carp_serializable/carp_serializable.dart';

part 'data_model.g.dart'; // 这将生成序列化代码

@CarpSerializable()
class Person {
  String name;
  int age;

  Person({required this.name, required this.age});

  // 从生成的代码中使用 factory 构造函数进行反序列化
  factory Person.fromMap(Map<String, dynamic> map) => _$PersonFromJson(map);

  // 使用生成的代码进行序列化
  Map<String, dynamic> toMap() => _$PersonToJson(this);
}

步骤 2: 生成序列化代码

在项目根目录下运行以下命令以生成序列化代码:

flutter pub run build_runner build

这将在你的项目目录中生成一个 data_model.g.dart 文件,其中包含序列化所需的代码。

步骤 3: 使用序列化和反序列化

现在,你可以使用 toMap() 方法序列化对象,并使用 fromMap() 方法反序列化对象。

void main() {
  // 创建一个 Person 对象
  Person person = Person(name: 'Alice', age: 30);

  // 序列化对象
  Map<String, dynamic> personMap = person.toMap();
  print('Serialized Person: $personMap');

  // 反序列化对象
  Person deserializedPerson = Person.fromMap(personMap);
  print('Deserialized Person: ${deserializedPerson.name}, Age: ${deserializedPerson.age}');
}

完整示例

以下是完整的代码示例,包括模型定义、生成代码命令以及使用示例:

data_model.dart

import 'package:carp_serializable/carp_serializable.dart';

part 'data_model.g.dart';

@CarpSerializable()
class Person {
  String name;
  int age;

  Person({required this.name, required this.age});

  factory Person.fromMap(Map<String, dynamic> map) => _$PersonFromJson(map);

  Map<String, dynamic> toMap() => _$PersonToJson(this);
}

main.dart

import 'data_model.dart';

void main() {
  Person person = Person(name: 'Alice', age: 30);

  Map<String, dynamic> personMap = person.toMap();
  print('Serialized Person: $personMap');

  Person deserializedPerson = Person.fromMap(personMap);
  print('Deserialized Person: ${deserializedPerson.name}, Age: ${deserializedPerson.age}');
}

pubspec.yaml(部分)

dependencies:
  flutter:
    sdk: flutter
  carp_serializable: ^x.y.z  # 替换为最新版本号

dev_dependencies:
  build_runner: ^x.y.z  # 确保安装了 build_runner

确保你已经安装了 build_runner,因为在生成序列化代码时需要用到它。

通过上述步骤,你就可以在 Flutter 项目中使用 carp_serializable 插件进行数据序列化和反序列化了。

回到顶部