You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter+Firebase:如何不查询数据库从本地类获取用户名

问题:无需查询数据库即可获取用户属性的方法?

我有两个页面:

  • 注册页面:在此处将用户信息保存至Firebase
  • 聊天页面:在此处需要调用用户信息

以下是注册页面的代码片段:

// 调用包含所有Firebase逻辑的类的变量
late final FirebaseCloudStorage _userService;

// 创建用户的方法
Future createUserAccount() async {
  if (_photo == null) return;
  try {
    setState(() {
      _isLoading = true;
    });
    await AuthService.firebase().createUser(
      email: _email.text,
      password: _password.text,
    );
    final userId = AuthService.firebase().currentUser?.id;
    final destination = 'user-profile-image/$userId';
    final ref = FirebaseStorage.instance.ref(destination);
    await ref.putFile(_photo!);
    imageUrl = await ref.getDownloadURL();
    _userService.createNewUser(
      userId: userId as String,
      userState: 'new',
      userImage: imageUrl as String,
      userFirstName: _userFirstName.text,
      userLastName: _userLastName.text,
      userCellNumber: _userCellphoneNumber.text,
      userCity: _userCity.text,
      userAreaCode: _userAreaCode.text,
      userAddress: _userAddress.text,
      userEmail: _email.text,
    );
}

包含云用户逻辑的类:

@immutable
class CloudUser {
  final String documentId;
  final String userId;
  final String userState;
  final String userImage;
  final String userFirstName;
  final String userLastName;
  final String userCellNumber;
  final String userCity;
  final String userAreaCode;
  final String userAddress;
  final String? userEmail;

  const CloudUser({
    required this.documentId,
    required this.userId,
    required this.userState,
    required this.userImage,
    required this.userFirstName,
    required this.userLastName,
    required this.userCellNumber,
    required this.userCity,
    required this.userAreaCode,
    required this.userAddress,
    required this.userEmail,
  });

  // 我试过调用这个方法但没用!
  // 我在聊天页面这么调用的:CloudUser.getFirstName()
  String getFirstName() {
    return userFirstName;
  }

  CloudUser.fromSnapshot(QueryDocumentSnapshot<Map<String, dynamic>> snapshot)
      : documentId = snapshot.id,
        userId = snapshot.data()[userIdColumn],
        userState = snapshot.data()[userStateColumn] ?? "",
        userImage = snapshot.data()[userImageColumn] ?? "",
        userFirstName = snapshot.data()[userFirstNameColumn] ?? "",
        userLastName = snapshot.data()[jobAreaCodeColumn] ?? "",
        userCellNumber = snapshot.data()[userCellNumberColumn] ?? "",
        userCity = snapshot.data()[userCityColumn] ?? "",
        userAreaCode = snapshot.data()[userAreaCodeColumn] ?? "",
        userAddress = snapshot.data()[userAddressColumn] ?? "",
        userEmail = snapshot.data()[userEmailColumn] ?? "";
}

与FirebaseCloudStorage交互的逻辑类:

class FirebaseCloudStorage {
  final user = FirebaseFirestore.instance.collection('user');

  Future<CloudUser> createNewUser({
    required String userId,
    required String userState,
    required String userImage,
    required String userFirstName,
    required String userLastName,
    required String userCellNumber,
    required String userCity,
    required String userAreaCode,
    required String userAddress,
    required String userEmail,
  }) async {
    final document = await user.add({
      userIdColumn: userId,
      userStateColumn: userState,
      userImageColumn: userImage,
      userFirstNameColumn: userFirstName,
      userLastNameColumn: userLastName,
      userCellNumberColumn: userCellNumber,
      userCityColumn: userCity,
      userAreaCodeColumn: userAreaCode,
      userAddressColumn: userAddress,
      userEmailColumn: userEmail,
    });
    final fetchedUser = await document.get();
    return CloudUser(
      documentId: fetchedUser.id,
      userId: userId,
      userState: userState,
      userImage: userImage,
      userFirstName: userFirstName,
      userLastName: userLastName,
      userCellNumber: userCellNumber,
      userCity: userCity,
      userAreaCode: userAreaCode,
      userAddress: userAddress,
      userEmail: userEmail,
    );
  }

// 我可以加个方法用用户ID从服务器获取数据,但我觉得没必要这么做

// 单例模式
  static final FirebaseCloudStorage _shared =
      FirebaseCloudStorage._sharedInstance();
  FirebaseCloudStorage._sharedInstance();
  factory FirebaseCloudStorage() => _shared;
}

有没有高效存储和检索这些数据的方法?


解决方案

1. 本地缓存用户信息(无需重复查库)

注册成功后,把CloudUser实例转成JSON格式保存到本地缓存(比如shared_preferences),聊天页面直接从缓存读取即可:

实现步骤:

  • 添加依赖:shared_preferences: ^2.2.2(根据实际版本调整)
  • 注册成功后存入缓存:
// 在createUserAccount方法中,调用完_userService.createNewUser后
final newUser = await _userService.createNewUser(
  // 传入注册时的参数
);
// 将CloudUser转为JSON
final userJson = {
  'documentId': newUser.documentId,
  'userId': newUser.userId,
  'userState': newUser.userState,
  'userImage': newUser.userImage,
  'userFirstName': newUser.userFirstName,
  'userLastName': newUser.userLastName,
  'userCellNumber': newUser.userCellNumber,
  'userCity': newUser.userCity,
  'userAreaCode': newUser.userAreaCode,
  'userAddress': newUser.userAddress,
  'userEmail': newUser.userEmail,
};
// 存入SharedPreferences
final prefs = await SharedPreferences.getInstance();
await prefs.setString('current_user', jsonEncode(userJson));
  • 聊天页面读取缓存:
// 在聊天页面初始化时执行
final prefs = await SharedPreferences.getInstance();
final userJsonString = prefs.getString('current_user');
if (userJsonString != null) {
  final userJson = jsonDecode(userJsonString);
  final currentUser = CloudUser(
    documentId: userJson['documentId'],
    userId: userJson['userId'],
    userState: userJson['userState'],
    userImage: userJson['userImage'],
    userFirstName: userJson['userFirstName'],
    userLastName: userJson['userLastName'],
    userCellNumber: userJson['userCellNumber'],
    userCity: userJson['userCity'],
    userAreaCode: userJson['userAreaCode'],
    userAddress: userJson['userAddress'],
    userEmail: userJson['userEmail'],
  );
  // 现在可以正常调用currentUser.getFirstName()
}

2. 利用Firebase Auth自定义Claims(适合少量关键属性)

如果只需要少量核心属性(比如名字、头像URL),可以把这些信息存到Firebase Auth的自定义Claims中,无需查询Firestore,直接通过Auth实例获取:

实现步骤:

  • 注册成功后设置自定义Claims:
// 在createUserAccount中,获取userId后执行
await FirebaseAuth.instance.currentUser?.updateClaims({
  'firstName': _userFirstName.text,
  'lastName': _userLastName.text,
  'imageUrl': imageUrl,
});
  • 聊天页面获取属性:
final user = FirebaseAuth.instance.currentUser;
if (user != null) {
  await user.reload(); // 确保获取最新的Claims
  final firstName = user.claims?['firstName'] as String?;
  final imageUrl = user.claims?['imageUrl'] as String?;
  // 直接使用这些属性
}

注意:自定义Claims适合存储少量、不敏感、不频繁变更的信息,更新Claims需要后端权限(或Firebase Functions),且客户端需调用reload才能获取最新值。

3. 全局状态管理(Provider/GetX/Bloc)

用状态管理工具将用户信息存入全局状态,注册成功后更新状态,聊天页面直接从全局状态读取:

以GetX为例:

  • 创建UserController:
class UserController extends GetxController {
  var currentUser = Rxn<CloudUser>();

  void setUser(CloudUser user) {
    currentUser.value = user;
  }
}
  • 注册页面设置全局用户:
final newUser = await _userService.createNewUser(...);
Get.put(UserController()).setUser(newUser);
  • 聊天页面获取用户:
final user = Get.find<UserController>().currentUser.value;
if (user != null) {
  print(user.getFirstName());
}

补充说明

你之前调用CloudUser.getFirstName()失败,是因为getFirstName()是实例方法,必须先创建CloudUser的实例才能调用,不能直接用类名调用。


内容的提问来源于stack exchange,提问作者user17281101

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 21:40:27