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

Null check operator cannot used on null value

这是我的聊天屏幕代码

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

'''

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

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

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

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

您在某处对变量使用了 !,但该变量为空。检查错误所在。

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";
  }}

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

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";
  }

}

深入研究您的代码后,我发现此函数从未被调用

doThisOnlaunch() async {
    await getMyInfoFromSharedPreference();
  }

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

String? chatRoomId, messageId = "";

并且在此方法中,您在 chatRoomId 上使用 !,它为 null。

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

这就是导致错误的原因。

解决方案

initState 上调用此方法喜欢

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

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

String chatRoomId="", messageId = "";

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