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

Flutter 2.0.2 Null check operator used on a null value

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

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

这是我遇到的错误:

The following _CastError was thrown building NotificationBanner(dirty): Null check operator used on a null value. The relevant error-causing widget was: NotificationBanner file:///Users/alexm/carebloom-flutter/lib/Views/homeview.dart:9:7

The following _CastError was thrown building AlertBanner(dirty): Null check operator used on a null value. The relevant error-causing widget was: AlertBanner file:///Users/alexm/carebloom-flutter/lib/Views/alerts_view.dart:57:15

The following _CastError was thrown building MessageOverView(dirty): Null check operator used on a null value. The relevant error-causing widget was: MessageOverView file:///Users/alexm/carebloom-flutter/lib/widgets/navbar.dart:41:16

这个有点不同

The following _CastError was thrown building SettingsView(dirty, dependencies: [_EffectiveTickerMode], state: _SettingsViewState#ddb1e(tickers: tracking 1 ticker)): Null check operator used on a null value. The relevant error-causing widget was: SettingsView file:///Users/alexm/carebloom-flutter/lib/widgets/navbar.dart:49:16

现在我假设错误出在 whatever widget 作为 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;
    });
  }
}

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

对我的 post 的评论帮助我确定了在哪里寻找我的问题!

这对我 运行 稍后遇到的另一个错误很有用。

由于这个问题,它最终成为 Firebase 中的某个东西,它的数据布局比我们实际使用的要旧。几乎来自 firebase 的文档之一缺少一个字段,这导致空检查运算符执行其工作并让我知道它收到了一个空值。

问题:

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

例如:

int? i;

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

解法:

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

    int? i;
    
    void main() {
      var local = i;
      if (local != null) {
        print(local.isEven);
      }
    }
    
  2. 您还可以使用 ?. 并在类型为 null 时提供默认值。

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