在Flutter项目中使用Firebase存储数据时,从Firebase实时数据库或者Firestore获取到的数据格式通常是动态的Map结构,直接操作这类数据很容易出现类型错误,也不利于代码的后续维护。将Firebase数据转换为Dart Pojo类,能够让数据操作更加类型安全,同时提升代码的可读性。

手动编写转换方法
手动编写转换逻辑是最基础的方式,适合数据结构简单、字段较少的场景。我们首先定义一个Dart类,然后为这个类添加fromMap和toMap方法,分别用于从Firebase数据解析和转换为Firebase可存储的格式。
以下是一个用户信息的Pojo类示例:
class User {
final String id;
final String name;
final int age;
final String email;
User({
required this.id,
required this.name,
required this.age,
required this.email,
});
// 从Firebase的Map数据转换为User对象
factory User.fromMap(Map<String, dynamic> map, String id) {
return User(
id: id,
name: map['name'] ?? '',
age: map['age'] ?? 0,
email: map['email'] ?? '',
);
}
// 将User对象转换为可存入Firebase的Map格式
Map<String, dynamic> toMap() {
return {
'name': name,
'age': age,
'email': email,
};
}
}
在使用时,从Firestore获取文档数据后,可以这样转换:
// 获取单个文档并转换为User对象
final docSnapshot = await FirebaseFirestore.instance.collection('users').doc('user_id_123').get();
if (docSnapshot.exists) {
final user = User.fromMap(docSnapshot.data()!, docSnapshot.id);
print('用户姓名:${user.name}');
}
使用json_serializable自动生成转换代码
当Pojo类的字段较多,或者数据结构复杂时,手动编写转换方法会非常繁琐,还容易出错。这时候可以使用json_serializable库自动生成转换逻辑,减少重复工作。
配置依赖
首先在pubspec.yaml中添加相关依赖:
dependencies:
flutter:
sdk: flutter
firebase_core: ^2.24.2
cloud_firestore: ^4.15.2
json_annotation: ^4.8.1
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^2.4.6
json_serializable: ^6.7.1
编写带注解的Pojo类
然后使用json_serializable的注解来标记类,让代码生成工具自动生成转换方法:
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class User {
final String id;
final String name;
final int age;
@JsonKey(name: 'email_address') // 如果Firebase中的字段名和类字段名不一致,可以用这个注解映射
final String email;
User({
required this.id,
required this.name,
required this.age,
required this.email,
});
// 自动生成的fromJson方法
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
// 自动生成的toJson方法
Map<String, dynamic> toJson() => _$UserToJson(this);
// 兼容Firebase的fromMap方法,内部调用fromJson
factory User.fromMap(Map<String, dynamic> map, String id) {
final json = Map<String, dynamic>.from(map);
json['id'] = id;
return User.fromJson(json);
}
// 转换为可存入Firebase的Map,内部调用toJson
Map<String, dynamic> toMap() {
final json = toJson();
json.remove('id'); // 存入Firebase时不需要存id字段,id通常是文档的标识
return json;
}
}
生成转换代码
在终端执行以下命令,生成对应的user.g.dart文件:
flutter pub run build_runner build --delete-conflicting-outputs
生成代码后,使用方式和手动编写的方式类似,但是不需要自己维护转换逻辑,字段新增或修改时只需要重新执行生成命令即可。
两种方法的对比和选择
| 对比项 | 手动编写转换 | json_serializable自动生成 |
|---|---|---|
| 适用场景 | 字段少、结构简单的小型类 | 字段多、结构复杂、需要频繁修改的类 |
| 维护成本 | 字段修改时需要手动同步修改转换方法 | 字段修改后只需重新生成代码,无需手动修改 |
| 出错概率 | 手动编写容易漏写字段或者类型错误 | 生成逻辑由库保证,出错概率低 |
| 学习成本 | 无额外学习成本 | 需要了解注解和代码生成的基本用法 |
注意事项
- Firebase实时数据库返回的数据可能是
Map<dynamic, dynamic>类型,需要先转换为Map<String, dynamic>再传入转换方法,避免类型错误。 - 如果Firebase中的字段可能为null,那么在Pojo类中对应的字段需要定义为可空类型,或者在转换时设置默认值,避免运行时报错。
- 使用
json_serializable时,如果Firebase的字段名和Dart类的字段名不一致,一定要使用@JsonKey注解做映射,否则会解析失败。 - 从Firebase获取的文档id通常不会存在文档的字段中,需要单独传入转换方法,不要尝试从原始数据里读取id字段。