Flutter 2.0.2 Null 检查运算符用于空值

Posted

技术标签:

【中文标题】Flutter 2.0.2 Null 检查运算符用于空值【英文标题】:Flutter 2.0.2 Null check operator used on a null value 【发布时间】:2021-06-17 02:09:26 【问题描述】:

虽然我知道这可能看起来像是重复的,有多少关于此错误的不同帖子,但我收到此错误是因为(我假设)是四个不同屏幕上的不同原因。

我的应用程序启动,但每当我尝试导航我的应用程序时,我最终都会收到红屏错误,因为它说屏幕中的一个小部件在空值上使用了空值检查运算符。

这是我得到的错误:

在构建 NotificationBanner(dirty) 时引发了以下 _CastError: 用于空值的空值检查运算符。 相关的导致错误的小部件是: NotificationBanner file:///Users/alexm/carebloom-flutter/lib/Views/homeview.dart:9:7

在构建 AlertBanner(dirty) 时引发了以下 _CastError: 用于空值的空值检查运算符。 相关的导致错误的小部件是: AlertBanner file:///Users/alexm/carebloom-flutter/lib/Views/alerts_view.dart:57:15

在构建 MessageOverView(dirty) 时引发了以下 _CastError: 用于空值的空值检查运算符。 相关的导致错误的小部件是: MessageOverView file:///Users/alexm/carebloom-flutter/lib/widgets/navbar.dart:41:16

这个有点不一样

在构建 SettingsView(dirty, dependencies: [_EffectiveTickerMode],状态:_SettingsViewState#ddb1e(代码:跟踪 1 个代码)): 用于空值的空值检查运算符。 相关的导致错误的小部件是: SettingsView file:///Users/alexm/carebloom-flutter/lib/widgets/navbar.dart:49:16

现在我假设错误位于作为 WidgetName(dirty) 返回的任何小部件中。所以每一个的代码都在下面。但是,我还想在所有这些之上提出一些问题,以更好地理解并帮助我在未来诊断问题。当它具有 WidgetName(dirty) 时,这究竟意味着什么是 (dity)?除了显示特定小部件的错误消息外,它还提供“相关的导致错误的小部件路径,是我应该查看的路径吗?

通知横幅:

  @override
  Widget build(BuildContext context) 
    return StreamBuilder<QuerySnapshot>(
        stream: FirebaseFirestore.instance
            .collection('alerts')
            .where('access',
                arrayContains: FirebaseAuth.instance.currentUser!.uid)
            .where('read', isEqualTo: false)
            //.orderBy('createdAt', descending: true)
            .snapshots(),
        builder: (context, snapshot) 
          if (!snapshot.hasData || snapshot.data!.docs.length <= 0) 
            return Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.only(
                    topLeft: Radius.circular(10),
                    topRight: Radius.circular(10),
                    bottomLeft: Radius.circular(10),
                    bottomRight: Radius.circular(10)),
                boxShadow: [
                  BoxShadow(
                    color: Colors.grey.withOpacity(0.5),
                    spreadRadius: 5,
                    blurRadius: 7,
                    offset: Offset(0, 3), // changes position of shadow
                  ),
                ],
              ),
              height: 60.0,
              child: Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.start,
                children: [
                  SizedBox(width: 10.0),
                  Icon(
                    Icons.check_box,
                    color: Colors.green,
                    size: MediaQuery.of(context).size.width * .1,
                  ),
                  SizedBox(width: 5.0),
                  Expanded(
                    child: AutoSizeText(
                      "No Current Messages or Alerts",
                      maxLines: 1,
                      maxFontSize: 20,
                      style:
                          TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                    ),
                  ),
                  //if (snapshot.hasData) SizedBox(width: 45),
                ],
              ),
            );
          
          Alert alert = Alert.fromFirestore(snapshot.data!.docs.first);
          return Card(
            //height: 60.0,
            child: InkWell(
                child: Row(
                  mainAxisSize: MainAxisSize.max,
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    SizedBox(width: 10.0),
                    Icon(
                      Icons.warning,
                      color: Colors.red,
                      size: MediaQuery.of(context).size.width * .1,
                    ),
                    SizedBox(width: 15.0),
                    Expanded(
                      child: AutoSizeText(
                        "New Alert for Your Patient",
                        maxLines: 1,
                        maxFontSize: 20,
                        style: TextStyle(
                            fontSize: 20, fontWeight: FontWeight.bold),
                      ),
                    ),
                    //if (snapshot.hasData) SizedBox(width: 45),
                    if (snapshot.hasData) Icon(Icons.arrow_right, size: 50)
                  ],
                ),
                onTap: () ),
            elevation: 12,
          );
        );
  

  Widget getIcon(snapshot) 
    if (snapshot.hasData) 
      return Icon(
        Icons.warning,
        color: Colors.red,
        size: 60,
      );
     else 
      return Icon(
        Icons.check_box,
        color: Colors.green,
        size: 60,
      );
    
  

警报横幅:

import 'package:carebloom/models/alert_model.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';

class AlertBanner extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return StreamBuilder<QuerySnapshot>(
        stream: FirebaseFirestore.instance
            .collection('alerts')
            .where('access',
                arrayContains: FirebaseAuth.instance.currentUser!.uid)
            .where('read', isEqualTo: false)
            .orderBy('createdAt', descending: true)
            .snapshots(),
        builder: (context, snapshot) 
          print(snapshot.hasData);
          print('alert has error');
          print(snapshot.hasError);
          if (snapshot.hasError) 
            print(snapshot.error);
          
          if (!snapshot.hasData || snapshot.data!.docs.length <= 0) 
            return Card(
              child: SizedBox(
                height: MediaQuery.of(context).size.height * .08,
                child: Row(
                  mainAxisSize: MainAxisSize.max,
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    SizedBox(width: 10.0),
                    Icon(
                      Icons.check_box,
                      color: Colors.green,
                      size: MediaQuery.of(context).size.width * .1,
                    ),
                    SizedBox(width: 5.0),
                    Expanded(
                      child: AutoSizeText(
                        "No Current Messages or Alerts",
                        maxLines: 1,
                        maxFontSize: 20,
                        style: TextStyle(
                            fontSize: 20, fontWeight: FontWeight.bold),
                      ),
                    ),
                    //if (snapshot.hasData) SizedBox(width: 45),
                  ],
                ),
              ),
            );
          
          Alert curAlert = Alert.fromFirestore(snapshot.data!.docs.elementAt(0));
          return Card(
            child: SizedBox(
              height: MediaQuery.of(context).size.height * .08,
              child: Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.start,
                children: [
                  SizedBox(width: 10.0),
                  Icon(
                    Icons.warning_rounded,
                    color: Colors.red,
                    size: MediaQuery.of(context).size.width * .1,
                  ),
                  SizedBox(width: MediaQuery.of(context).size.width * .08),
                  Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      AutoSizeText(
                          curAlert.desc!.toLowerCase().capitalizeFirstofEach,
                          maxLines: 1,
                          maxFontSize: 20,
                          style: TextStyle(
                              fontSize: 20, fontWeight: FontWeight.bold)),
                      AutoSizeText(
                        curAlert.fname + ' ' + '$curAlert.lname[0]' + '.',
                        maxLines: 1,
                        maxFontSize: 20,
                        style: TextStyle(
                          fontSize: 18,
                        ),
                      ),
                    ],
                  ),
                  Spacer(), //SizedBox(width: MediaQuery.of(context).size.width * .1),
                  Icon(Icons.arrow_right, size: 50)
                  //if (snapshot.hasData) SizedBox(width: 45),
                ],
              ),
            ),
          );
        );
  


extension StringFormatExtension on String 
  String get capitalizeFirstofEach => this
      .split(" ")
      .map((str) => str[0].toUpperCase() + str.substring(1))
      .join(" ");

MessageOverView:

import 'package:auto_size_text/auto_size_text.dart';
import 'package:carebloom/Services/auth.dart';
import 'package:carebloom/models/last_message_model.dart';
import 'package:carebloom/models/converstaions.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';

class MessageOverView extends StatelessWidget 
  // This widget is the root of your application.

  final AuthService _auth = AuthService();
  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      appBar: new AppBar(
        centerTitle: true,
        automaticallyImplyLeading: false,
        backgroundColor: Color(0xFF6cc5de),
        title: AutoSizeText(
          'Messages',
          maxLines: 1,
          style: GoogleFonts.raleway(
              fontWeight: FontWeight.bold,
              fontSize: 35,
              textStyle: TextStyle(
                color: Colors.black,
              )),
          textAlign: TextAlign.center,
        ),
      ),
      body: Container(
        padding: EdgeInsets.all(2.5),
        decoration: BoxDecoration(
            gradient: LinearGradient(
                begin: Alignment.topRight,
                end: Alignment.bottomCenter,
                colors: [Color(0xFFb5e2ee), Colors.white])),
        child: Container(
          child: StreamBuilder<QuerySnapshot>(
              stream: FirebaseFirestore.instance
                  .collection('messages')
                  .where('access',
                      arrayContains: FirebaseAuth.instance.currentUser!.uid)
                  //FirebaseAuth.instance.currentUser.uid, isEqualTo: true)
                  .snapshots(),
              builder: (context, snapshot) 
                if (!snapshot.hasData) 
                  return Container();
                
                print("after message list query*****************************");
                print(snapshot.data!.docs.toString());
                print(snapshot.data!.docs.length);
                return ListView.builder(
                    itemCount: 1,
                    itemBuilder: (context, pos) 
                      LastMessage msg = LastMessage.fromFirestore(
                          snapshot.data!.docs.elementAt(pos));
                      print('error before or after??????/');
                      print(snapshot.data!.docs.contains(msg.id));
                      return ConversationList(
                        patient: msg.fname! + ' ' + msg.lname!,
                        name: msg.author,
                        messageText: msg.text,
                        imageUrl: msg.photoURL,
                        time: DateFormat('MMM d, h:mma')
                            .format(msg.msgRecieved!.toDate()),
                        isMessageRead: false,
                        pos: pos,
                        id: msg.id,
                      );
                    );
              ),
        ),
      ),
    );
  

设置视图:

import 'dart:io';

import 'package:carebloom/Screens/login.dart';
import 'package:carebloom/Services/auth.dart';
import 'package:carebloom/Services/image_picker_handler.dart';
import 'package:carebloom/models/user.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';

class SettingsView extends StatefulWidget 
  SettingsView(Key? key) : super(key: key);

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


class _SettingsViewState extends State<SettingsView>
    with TickerProviderStateMixin, ImagePickerListener 
  // This widget is the root of your application.
  final AuthService _auth = AuthService();

  File? _image;
  AnimationController? _controller;
  late ImagePickerHandler imagePicker;

  @override
  void initState() 
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 500),
    );

    imagePicker = new ImagePickerHandler(this, _controller);
    imagePicker.init();
  

  @override
  void dispose() 
    _controller!.dispose();
    super.dispose();
  

  @override
  Widget build(BuildContext context) 
    print('Before query settings');

    return Stack(children: [
      StreamBuilder<DocumentSnapshot>(
          stream: FirebaseFirestore.instance
              .collection('users')
              .doc(FirebaseAuth.instance.currentUser!.uid)
              .get()
              .asStream(),
          builder: (context, snapshot) 
            if (!snapshot.hasData) 
              return Container();
            
            LUser user = LUser.fromFirestore(snapshot.data!);

            return Column(
              children: [
                Container(
                  width: double.infinity,
                  child: Center(
                    child: CircleAvatar(
                      backgroundColor: Colors.white,
                      //backgroundImage: NetworkImage(user.photo),
                      foregroundColor: Colors.grey[600],
                      child: null == user.photo
                          ? CircleAvatar(
                              child: Icon(
                                Icons.person,
                                size: 210,
                                color: Colors.grey[600],
                              ),
                              backgroundColor: Colors.white,
                              radius: 110,
                            )
                          : CircleAvatar(
                              backgroundImage: NetworkImage(user.photo!),
                              backgroundColor: Colors.white,
                              radius: 110,
                            ),
                      radius: 110,
                    ),
                  ),
                ),
                ElevatedButton(
                  onPressed: () => imagePicker.showDialog(context),
                  child: Icon(Icons.camera_alt_outlined),
                  style: ElevatedButton.styleFrom(
                    primary: Color(0xFF3E8094),
                    onPrimary: Colors.white,
                    shadowColor: Color(0xFF6cc5de),
                    elevation: 5,
                    padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(20.0),
                        side: BorderSide(color: Color(0xFF6CC5DE))),
                  ),
                ),
                Container(
                  width: double.infinity,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      SizedBox(
                        height: 20,
                      ),
                      Text(
                        'Name: ' + user.fname! + ' ' + user.lname!,
                        style: TextStyle(
                          fontSize: 24,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      SizedBox(
                        height: 20,
                      ),
                      Text(
                        'Email: ' + user.email!,
                        style: TextStyle(
                          fontSize: 24,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      SizedBox(
                        height: 20,
                      ),
                    ],
                  ),
                ),
                Container(
                  width: double.infinity,
                  height: 50,
                  child: ElevatedButton(
                      child: Text('Sign Out'),
                      style: ElevatedButton.styleFrom(
                        primary: Color(0xFF3E8094),
                        onPrimary: Colors.white,
                        shadowColor: Color(0xFF6cc5de),
                        elevation: 5,
                        padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
                        shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(20.0),
                            side: BorderSide(color: Color(0xFF6CC5DE))),
                      ),
                      onPressed: () async 
                        await _auth.signOut();
                        Navigator.of(context).push(MaterialPageRoute(
                            builder: (_) => LoginScreen(),
                            fullscreenDialog: true));
                      
                      // 
                      ),
                ),
              ],
            );
          ),
    ]);
  

  @override
  userImage(File? _image) 
    setState(() 
      this._image = _image;
    );
  

到目前为止,我已经检查了所有有空检查但无法修复的内容。 我已经将颤振升级到 2.0.2,运行颤振 pub 缓存修复,并通过两次确保这些事情正确完成。我不确定我错过了什么,但我认为它实际上在代码中。

【问题讨论】:

是的,引用文件的引用行号应该为您提供每个错误来自何处的线索。 【参考方案1】:

对我帖子的评论帮助我确认了在哪里寻找我的问题!

这对于我后来遇到的另一个错误很有用。

由于这个问题,它最终在 Firebase 中具有与我们实际使用的数据布局相比旧的数据布局。 firebase 中的几乎一个文档都缺少一个字段,这导致空检查运算符完成它的工作,并让我知道它收到了一个空值。

【讨论】:

您能进一步解释一下吗?哪里缺少什么字段? 当然!我在颤振中的代码正在寻找要显示的特定字段,并且 firebase 中有一些对象缺少一两个字段,因此它给了我一个错误。我进入 firebase 并将字段添加到对象并重新启动我的应用程序,它运行良好。这对我正在做的事情更具体一点,而不是对任何有这个问题的人的包罗万象。我认为我的用户对象缺少导致此问题的性别字段,但它可能是其他人的其他字段。【参考方案2】:

问题:

此错误通常发生在使用 Bang ! 运算符(也称为空断言运算符)来抛弃可空性时。

例如:

int? i;

void main() 
  print(i!.isEven); // Runtime error: Null check operator used on a null value


解决方案:

    当您不确定类型的可空性时,建议使用局部变量并对其进行空值检查,而不是使用 bang 运算符。

    int? i;
    
    void main() 
      var local = i;
      if (local != null) 
        print(local.isEven);
      
    
    

    如果类型为null,您也可以使用?. 并提供默认值。

    int? i;
    
    void main() 
      print(i?.isEven ?? true);
    
    

【讨论】:

局部变量是我要走的路

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

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

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

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

为啥我在 Flutter 测试期间使用 rootBundle.load 得到“对空值使用空检查运算符”?

Flutter StreamBuilder 与 initialData 和 null-awareness

flutter/dart 语法点记录