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

Flutter迁移后创建组时currentUser为空,类型转换错误求助

问题:Flutter迁移后创建组时currentUser类型转换报错(Null转UserModel)

我正在开发一个通过groupID创建和加入组的项目,Flutter迁移后,用户创建组时出现currentUser相关的类型转换错误,Null无法转为UserModel。添加了null判断但问题依旧。

错误栈信息

Syncing files to device MO 01K...
I/flutter (15786): the user uid is Fts7cm617ShS79JxqGRUOdsz7zo2
Reloaded 1 of 2161 libraries in 3,199ms (compile: 176 ms, reload: 1313 ms, reassemble: 1238 ms).
I/flutter (15786): the user uid is Fts7cm617ShS79JxqGRUOdsz7zo2
I/flutter (15786): User is available!
E/flutter (15786): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Null' is not a subtype of type 'UserModel' in type cast
E/flutter (15786): #0      _OurAddBookState._addBook (package:jattendence/Admin/screens/addBook/addBook.dart:108:64)
E/flutter (15786): #1      _OurAddBookState.build.<anonymous closure> (package:jattendence/Admin/screens/addBook/addBook.dart:240:25)
E/flutter (15786): #2      _InkResponseState.handleTap (package:flutter/src/material/ink_well.dart:1072:21)
E/flutter (15786): #3      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:253:24)

UserModel类代码

import 'package:cloud_firestore/cloud_firestore.dart';

class UserModel {
  String? uid;
  String? email;
  Timestamp? accountCreated;
  String? fullName;
  String? groupId;
  String? notifToken;

  UserModel({
    this.uid,
    this.email,
    this.accountCreated,
    this.fullName,
    this.groupId,
    this.notifToken,
  });

  UserModel.fromDocumentSnapshot({required DocumentSnapshot <Map<String,dynamic>> doc}) {
    uid = doc.id;
    email = doc.data()?['email'];
    accountCreated = doc.data()?['accountCreated'];
    fullName = doc.data()?['fullName'];
    groupId = doc.data()?['groupId'];
    notifToken = doc.data()?['notifToken'];
  }
}

创建组时调用currentUser的相关代码

class OurAddBook extends StatefulWidget {
  final bool? onGroupCreation;
  final bool? onError;
  final String? groupName;
  final UserModel? currentUser;

  OurAddBook({
    this.onGroupCreation,
    this.onError,
    this.groupName,
    this.currentUser,
  });
  @override
  _OurAddBookState createState() => _OurAddBookState();
}

class _OurAddBookState extends State<OurAddBook> {
  final addBookKey = GlobalKey<ScaffoldState>();

  TextEditingController _bookNameController = TextEditingController();
  TextEditingController _authorController = TextEditingController();
  TextEditingController _lengthController = TextEditingController();

  DateTime _selectedDate = DateTime.now();

  initState() {
    super.initState();
    _selectedDate = DateTime(_selectedDate.year, _selectedDate.month,
        _selectedDate.day, _selectedDate.hour, 0, 0, 0, 0);
  }

  Future<void> _selectDate() async {
    final DateTime? picked = await showDatePicker(
        context: context,
        initialDate: DateTime.now(),
        firstDate: DateTime.now(),
        lastDate: DateTime(2222));

    if (picked != null && picked != _selectedDate) {
      setState(() {
        _selectedDate = DateTime(picked.year, picked.month, picked.day,
            _selectedDate.hour, 0, 0, 0, 0);
      });
    }
  }

  Future _selectTime() async {
    await showDialog<int>(
      context: context,
      builder: (BuildContext context) {
        int _currentIntValue = 0;
        return NumberPicker(
          value: _currentIntValue,
          minValue: 0,
          maxValue: 23,
          infiniteLoop: true, onChanged: (int value) {  },
        );
      },
    ).then(( value) {
      if (value != null) {
        setState(() {
          _selectedDate = DateTime(_selectedDate.year, _selectedDate.month,
              _selectedDate.day, value, 0, 0, 0, 0);
        });
      }
    });
  }

  void _addBook(BuildContext context, String? groupName, BookModel? book) async {
    String _returnString;

    if (_selectedDate.isAfter(DateTime.now().add(Duration(days: 1)))) {

        if (widget.currentUser == null) {
          print('current user not available');
        } else {
          print('User is available!');
          if (widget.onGroupCreation!) {
            _returnString =
            await DBFuture().createGroup(
                groupName!, widget.currentUser?.getCurrentUser as UserModel, book!); // 报错位置
          } else if (widget.onError!) {
            _returnString =
            await DBFuture().addCurrentBook(
                widget.currentUser?.groupId as String, book!);
          } else {
            _returnString =
            await DBFuture().addNextBook(
                widget.currentUser?.groupId as String, book!);
          }

          if (_returnString == "success") {
            Navigator.pushAndRemoveUntil(
                context,
                MaterialPageRoute(
                  builder: (context) => OurRoot(),
                ),
                    (route) => false);
          }
      }
    }
  }
}

我试过StackOverflow旧方案、Firestore 2.0迁移文档,用FirebaseAuth也没解决。现在需要正确获取Firestore中当前用户的UserModel信息来完成组创建。


解决方案

1. 定位核心问题

报错行widget.currentUser?.getCurrentUser as UserModel存在两个致命问题:

  • getCurrentUser方法在你的UserModel类中未定义,调用后必然返回null
  • 强行用as UserModel转换null,直接触发类型转换异常

你虽然做了widget.currentUser == null的判断,但后续调用不存在的方法导致结果为null,绕过了判断逻辑引发报错。

2. 修复步骤

步骤1:移除不存在的方法调用

widget.currentUser本身就是UserModel类型,直接传入即可,无需调用不存在的getCurrentUser:

// 替换报错行
_returnString = await DBFuture().createGroup(
    groupName!, widget.currentUser!, book!);

步骤2:完善全链路null安全检查

避免强制解包引发的空指针,对所有必要参数做非空校验:

void _addBook(BuildContext context, String? groupName, BookModel? book) async {
  String _returnString;

  if (_selectedDate.isAfter(DateTime.now().add(Duration(days: 1)))) {
    // 先校验核心参数非空
    if (widget.currentUser == null) {
      print('current user not available');
      return;
    }
    if (widget.onGroupCreation == null || groupName == null || book == null) {
      print('缺少创建组的必要参数');
      return;
    }

    print('User is available!');
    if (widget.onGroupCreation!) {
      _returnString = await DBFuture().createGroup(
          groupName, widget.currentUser!, book);
    } else if (widget.onError == true) {
      if (widget.currentUser!.groupId == null) {
        print('用户groupId为空');
        return;
      }
      _returnString = await DBFuture().addCurrentBook(
          widget.currentUser!.groupId!, book);
    } else {
      if (widget.currentUser!.groupId == null) {
        print('用户groupId为空');
        return;
      }
      _returnString = await DBFuture().addNextBook(
          widget.currentUser!.groupId!, book);
    }

    if (_returnString == "success") {
      Navigator.pushAndRemoveUntil(
          context,
          MaterialPageRoute(builder: (context) => OurRoot()),
              (route) => false);
    }
  }
}

步骤3:确保currentUser正确传入页面

如果widget.currentUser本身就是null,说明页面跳转时没有正确传递用户数据。需要在跳转前从Firebase拉取完整的UserModel:

// 示例:从FirebaseAuth获取uid,再从Firestore拉取用户数据
final firebaseUser = FirebaseAuth.instance.currentUser;
if (firebaseUser != null) {
  final doc = await FirebaseFirestore.instance.collection('users').doc(firebaseUser.uid).get();
  final userModel = UserModel.fromDocumentSnapshot(doc: doc);
  Navigator.push(context, MaterialPageRoute(
    builder: (context) => OurAddBook(currentUser: userModel, ...)
  ));
}

步骤4:优化UserModel的空安全(可选)

给UserModel的核心字段添加非空约束,或在解析时处理空值,避免后续使用时出现意外null:

// 修改构造函数,确保uid非空
UserModel({
  required this.uid,
  this.email,
  this.accountCreated,
  this.fullName,
  this.groupId,
  this.notifToken,
});

UserModel.fromDocumentSnapshot({required DocumentSnapshot <Map<String,dynamic>> doc}) {
  uid = doc.id; // doc.id不会为null
  email = doc.data()?['email'] ?? ''; // 空值替换为默认值
  accountCreated = doc.data()?['accountCreated'];
  fullName = doc.data()?['fullName'] ?? '';
  groupId = doc.data()?['groupId'];
  notifToken = doc.data()?['notifToken'];
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 01:25:37