空值检查运算符不能用于空值

Posted

技术标签:

【中文标题】空值检查运算符不能用于空值【英文标题】:Null check operator cannot used on null value 【发布时间】:2021-11-03 19:47:33 【问题描述】:

这是我的聊天屏幕代码

import 'package:flutter/material.dart';
import 'package:messenger/helperfunction/sharedpref_helper.dart';
import 'package:messenger/services/database.dart';
import 'package:random_string/random_string.dart';

class ChatScreen extends StatefulWidget 
  final String chatWithusername, name;
  ChatScreen(this.chatWithusername, this.name);

  @override
  _ChatScreenState createState() => _ChatScreenState();


class _ChatScreenState extends State<ChatScreen> 
  String? chatRoomId, messageId = "";
  String? myName, myProfilePic, myUserName, myEmail;
  TextEditingController messageEditingController = TextEditingController();

  getMyInfoFromSharedPreference() async 
    myName = await SharedPreferenceHelper().getDisplayName();
    myProfilePic = await SharedPreferenceHelper().getUserProfileUrl();
    myUserName = await SharedPreferenceHelper().getUserName();
    myEmail = await SharedPreferenceHelper().getUserEmail();

    chatRoomId = getChatRoomIdByUsername(widget.chatWithusername, myUserName);
  

  getChatRoomIdByUsername(String? a, String? b) 
    if (a!.substring(0, 1).codeUnitAt(0) > b!.substring(0, 1).codeUnitAt(0)) 
  return "$b\_$a";
   else 
  return "$a\_$b";
  
addMessage(bool sentClicked) 
   if (messageEditingController.text != "") 
  String message = messageEditingController.text;

  var lastMessageTs = DateTime.now();

  Map<String, dynamic> messageInfoMap = 
    "message": message,
    "sentBy": myUserName,
    'ts': lastMessageTs,
    "imgUrl": myProfilePic
  ;
  //Gentrate the message id
  if (messageId == "") 
    messageId = randomAlphaNumeric(12);
  

  DatabaseMethods()
      .addMessage(chatRoomId!, messageId!, messageInfoMap)
      .then((value) 
    Map<String, dynamic>? lastMessageInfoMap = 
      "lastmessage": message,
      "lastMessageSendTs": lastMessageTs,
      "lastMessageSendBy": myUserName
    ;

    DatabaseMethods()
        .updateLastmessageSend(chatRoomId!, lastMessageInfoMap);

    if (sentClicked) 
      messageEditingController.text = "";

      messageId = "";
    
  );




  getAnfSentMessages() async 

  doThisOnlaunch() async 
 await getMyInfoFromSharedPreference();


@override
Widget build(BuildContext context) 
return Scaffold(
  appBar: AppBar(
    title: Text(widget.name),
  ),
  body: Container(
    child: Stack(
      children: [
        Container(
          alignment: Alignment.bottomCenter,
          child: Container(
            color: Colors.black.withOpacity(0.8),
            padding: EdgeInsets.symmetric(
              horizontal: 6,
              vertical: 8,
            ),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: messageEditingController,
                    onChanged: (value) 
                      addMessage(false);
                    ,
                    style: TextStyle(color: Colors.white),
                    decoration: InputDecoration(
                        hintText: "   Type a message",
                        hintStyle: TextStyle(
                            color: Colors.white.withOpacity(0.6))),
                  ),
                ),
                GestureDetector(
                    onTap: () 
                      addMessage(true);
                    ,
                    child: Icon(Icons.send, color: Colors.white))
              ],
            ),
          ),
        )
      ],
    ),
  ),
 );
 

这是我的数据库;

    import 'package:cloud_firestore/cloud_firestore.dart';
// ignore: unused_import
import 'package:firebase_core/firebase_core.dart';

class DatabaseMethods 
  Future addUserInfoToDB(
      String userId, Map<String, dynamic> userInfoMap) async 
    return FirebaseFirestore.instance
        .collection("users")
        .doc(userId)
        .set(userInfoMap);
  

  Future<Stream<QuerySnapshot>> getUserByUserName(String username) async 
    return FirebaseFirestore.instance
        .collection("users")
        .where("username", isEqualTo: username)
        .snapshots();
  

  Future addMessage(String chatRoomId, String messageId,
      Map<String, dynamic> messageInfoMap) async 
    return FirebaseFirestore.instance
        .collection("chatRooms")
        .doc(chatRoomId)
        .collection("chats")
        .doc(messageId)
        .set(messageInfoMap);
  

  updateLastmessageSend(
      String chatRoomId, Map<String, dynamic> lastMessageInfoMap) 
    return FirebaseFirestore.instance
        .collection("chatRooms")
        .doc(chatRoomId)
        .update(lastMessageInfoMap);
  

  createChatRoom(
      String chatRoomId, Map<String, dynamic> chatRoomInfoMap) async 
    final snapShot = await FirebaseFirestore.instance
        .collection("chatrooms")
        .doc(chatRoomId)
        .get();

    if (snapShot.exists) 
      //chatroom already exits
      return true;
     else 
      //chatRoom does not exit:
      return FirebaseFirestore.instance
          .collection("chatrooms")
          .doc(chatRoomId)
          .set(chatRoomInfoMap);
    
  

当我运行此代码并开始在 textformfield 中输入时,我收到以下错误: '''

════════ Exception caught by widgets 
═══════════════════════════════════════════
The following _CastError was thrown while calling onChanged:
Null check operator used on a null value

When the exception was thrown, this was the stack
#0      _ChatScreenState.addMessage
package:messenger/view/chatscreen.dart:54
#1      _ChatScreenState.build.<anonymous closure>
package:messenger/view/chatscreen.dart:103
#2      EditableTextState._formatAndSetValue
package:flutter/…/widgets/editable_text.dart:2298
#3      EditableTextState.updateEditingValue
package:flutter/…/widgets/editable_text.dart:1749
#4      TextInput._handleTextInputInvocation
 package:flutter/…/services/text_input.dart:1351

'''

输入后,当我点击发送图标时,出现如下错误:

''' ════════ 手势捕获的异常 ═════════════════════════════════════════╕ 用于空值的空检查运算符

════════════════════════════════════════════════════════════════════════

''' 谁能帮忙解决这个问题

【问题讨论】:

我看到的唯一null 检查是在chatRoomId!, messageId! 上完成的,其中一个值是null 【参考方案1】:

深入研究您的代码后,我可以看到从未调用过此函数

doThisOnlaunch() async 
    await getMyInfoFromSharedPreference();
  

所以getMyInfoFromSharedPreference() 函数永远不会被调用 所以chatRoomId 没有被初始化,它永远是 null 因为这段代码

String? chatRoomId, messageId = "";

在这种方法中,您在chatRoomId 上使用!,它是空的。

DatabaseMethods()
          .addMessage(chatRoomId!, messageId!, messageInfoMap).then((value) ...

所以这就是导致错误的原因。

解决方案

initStatelike 上调用 tis 方法

String? chatRoomId, messageId = "";
      String? myName, myProfilePic, myUserName, myEmail;
      TextEditingController messageEditingController = TextEditingController();
    
    
      @override
      void initState() 
        super.initState();
        doThisOnlaunch();
      
      .
      .
      .

或者只是用一个值启动chatRoomId并将它们声明为不可为空的字符串

String chatRoomId="", messageId = "";

请注意,第二个解决方案只会停止错误,但您的代码将无法正常运行

【讨论】:

感谢您的帮助,还需要添加 "late String chatRoomId, messageId = "";" 不客气。添加late意味着这些字段不可为空,但会在应用的后期初始化,所以使用时要小心。【参考方案2】:
getChatRoomIdByUsername(String? a, String? b) 
    if (a!.substring(0, 1).codeUnitAt(0) > b!.substring(0, 1).codeUnitAt(0)) 
  return "$b\_$a";
   else 
  return "$a\_$b";
  

如果函数依赖于此,为什么要允许可空变量?

getChatRoomIdByUsername(required String a,required String b) 
    if (a.substring(0, 1).codeUnitAt(0) > b.substring(0, 1).codeUnitAt(0)) 
  return "$b\_$a";
   else 
  return "$a\_$b";
  

【讨论】:

如果我更改所需的字符串,则会显示错误:此处不能有修饰符“必需”。尝试删除“必需”。 getChatRoomIdByUsername(required String a,required String b) 检查您的代码是否缺少大括号 【参考方案3】:

您在某个变量上使用了!,而该变量为空。检查错误所在。

【讨论】:

我不知道如何找到它。我对扑腾完全陌生。你能帮忙解决这个错误吗

以上是关于空值检查运算符不能用于空值的主要内容,如果未能解决你的问题,请参考以下文章

用于空值的空值检查运算符

Flutter:FCM未处理异常:空值检查运算符用于空值

用于空值 Flutter 的空值检查运算符

Flutter Bloc Test:空值检查运算符用于空值(空安全)

Firebase.initializeApp() 给出错误:空值检查运算符用于空值

SharedPreferences.getInstance() 正在抛出 _CastError(空值检查运算符用于空值)