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

Flutter中如何从Firestore读取数据映射到UserModel?

问题解决:Firestore读取数据映射到UserModel失败

核心问题:Firestore中存储的time字段是Timestamp类型,你的UserModel.fromJson方法直接将其赋值给DateTime类型变量,导致类型转换错误。

以下是修正后的完整代码:

1. 修正UserModel.dart

class UserModel {
  String? name;
  String? bio;
  String? dpUrl;
  String? email;
  String? uid;
  DateTime? time;
  List<String>? followers;
  List<String>? followings;

  UserModel({
    required this.name,
    required this.bio,
    required this.dpUrl,
    required this.email,
    required this.uid,
    required this.time,
    required this.followers,
    required this.followings,
  });

  // 修复Timestamp转DateTime的逻辑
  UserModel.fromJson(Map<String, dynamic> json) {
    name = json['name'];
    bio = json['bio'];
    dpUrl = json['dpUrl'];
    email = json['email'];
    uid = json['uid'];
    // 判断是否为Timestamp类型,转换为DateTime
    if (json['time'] is Timestamp) {
      time = (json['time'] as Timestamp).toDate();
    } else {
      // 兼容其他可能的时间格式(比如字符串)
      time = DateTime.tryParse(json['time'].toString());
    }
    followers = json['followers']?.cast<String>() ?? [];
    followings = json['followings']?.cast<String>() ?? [];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data['name'] = name;
    data['bio'] = bio;
    data['dpUrl'] = dpUrl;
    data['email'] = email;
    data['uid'] = uid;
    // 存回Firestore时转成Timestamp
    data['time'] = time != null ? Timestamp.fromDate(time!) : null;
    data['followers'] = followers;
    data['followings'] = followings;
    return data;
  }
}

2. 修正Database类

取消readUser方法的注释,并添加空值防护:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_say/model/user_model.dart';

class Database {
  final String? uid;

  Database({required this.uid});

  final userdataRef = FirebaseFirestore.instance.collection('userdata');

  Future<UserModel?> readUser() async {
    // 先判断uid是否为空,避免无效请求
    if (uid == null || uid!.isEmpty) {
      return null;
    }
    
    final docUser = userdataRef.doc(uid);
    final snapshot = await docUser.get();

    if (snapshot.exists && snapshot.data() != null) {
      return UserModel.fromJson(snapshot.data()!);
    }
    return null;
  }
}

3. 修正ProfilePage.dart

处理snapshot.data为null的情况,避免空指针异常:

import 'package:flutter/material.dart';
import 'package:flutter_say/model/user_model.dart';
import 'package:flutter_say/services/database.dart';

class ProfilePage extends StatefulWidget {
  final String uid;
  const ProfilePage({
    super.key,
    required this.uid,
  });

  @override
  State<ProfilePage> createState() => _ProfilePageState();
}

class _ProfilePageState extends State<ProfilePage> {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<UserModel?>(
      future: Database(uid: widget.uid).readUser(),
      builder: (context, snapshot) {
        if (snapshot.hasError) {
          return Center(
            child: Text('错误:${snapshot.error.toString()}'), // 显示具体错误信息便于排查
          );
        }
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(
            child: CircularProgressIndicator(),
          );
        }
        
        final userData = snapshot.data;
        if (userData == null) {
          return const Center(
            child: Text('用户数据不存在'),
          );
        }
        
        return SafeArea(
          child: ListTile(
            title: Text('Name - ${userData.name ?? "未设置"}'),
            subtitle: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text('Bio - ${userData.bio ?? "无简介"}'),
                Text('邮箱 - ${userData.email ?? "未绑定"}'),
              ],
            ),
            leading: userData.dpUrl != null 
                ? CircleAvatar(backgroundImage: NetworkImage(userData.dpUrl!))
                : const CircleAvatar(child: Icon(Icons.person)),
          ),
        );
      },
    );
  }
}

额外排查点

  • 确认Firestore的userdata集合中,存在以当前用户uid命名的文档,且字段名(如name、dpUrl、time)与UserModel中的键完全一致(大小写敏感)。
  • 检查Firestore安全规则,确保当前用户有权限读取userdata集合中的文档。
  • 运行前先清理项目缓存(flutter clean)并重新构建。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 08:27:07