【问题标题】:Flutter : Unhandled Exception: Null check operator used on a null valueFlutter:未处理的异常:对空值使用空检查运算符
【发布时间】:2022-01-17 22:01:10
【问题描述】:

我正在尝试通过按“处理订单”按钮导航到新屏幕,但我不断收到错误 [VERBOSE-2:ui_dart_state.cc(209)] 未处理的异常:空检查运算符用于空值。我不确定错误到底发生在哪里。

我已经为此苦苦挣扎了一段时间。这可能是什么问题?

class CartScreen extends StatefulWidget {
  const CartScreen({
    Key? key,
  }) : super(key: key);

  static const routeName = '/cart-screen';

  @override
  State<CartScreen> createState() => _CartScreenState();
}

class _CartScreenState extends State<CartScreen> {
  final user = FirebaseAuth.instance.currentUser;  

  final TextEditingController deliveryNoteController = TextEditingController();
  bool isLoading = false;

  @override
  Widget build(BuildContext context) {
    final cart = Provider.of<Cart>(context);
    return isLoading
        ? const LoadingSpinner()
        : Scaffold(
            appBar: AppBar(
              automaticallyImplyLeading: false,
              elevation: 0,
              iconTheme: IconThemeData(color: Colors.blueGrey[900]),
              title: const Text(
                'Order Summary',
                style: TextStyle(color: Colors.black),
              ),
            ),
            body: cart.totalAmount <= 0
                ? const EmptyCartScreen()
                : SingleChildScrollView(
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 15.0),
                      child: Column(
                        children: <Widget>[
                          StreamBuilder<DocumentSnapshot>(
                              stream: FirebaseFirestore.instance
                                  .collection('users')
                                  .doc(user!.uid)
                                  .snapshots(),
                              builder: (context, snapshot) {
                                if (snapshot.hasError) {
                                  return const Text(
                                      'Oops, something went wrong.');
                                }
                                if (!snapshot.hasData) {
                                  return const LoadingSpinner();
                                }
                                DocumentSnapshot? doc = snapshot.data;
                                return Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    ListView.builder(
                                      physics:
                                          const NeverScrollableScrollPhysics(),
                                      shrinkWrap: true,
                                      scrollDirection: Axis.vertical,
                                      itemCount: cart.items.length,
                                      itemBuilder: (context, i) => CartItem(
                                        cart.items.values.toList()[i].id,
                                        cart.items.keys.toList()[i],
                                        cart.items.values.toList()[i].price,
                                        cart.items.values.toList()[i].quantity,
                                        cart.items.values
                                            .toList()[i]
                                            .title
                                            .toString(),
                                      ),
                                    ),
                                    Row(
                                      children: [
                                        const Text(
                                          'Delivery Address',
                                          style: TextStyle(
                                            fontWeight: FontWeight.w600,
                                            fontSize: 16.0,
                                          ),
                                        ),
                                        const Spacer(),
                                        TextButton(
                                          child: const Text('Edit'),
                                          onPressed: () {
                                            showModalBottomSheet(
                                              context: context,
                                              builder: (context) =>
                                                  const Padding(
                                                padding: EdgeInsets.symmetric(
                                                  horizontal: 20.0,
                                                  vertical: 30.0,
                                                ),
                                                child: EditDeliveryInfoForm(),
                                              ),
                                            );
                                          },
                                        ),
                                      ],
                                    ),
                                    Column(
                                      children: [
                                        ListTile(
                                          horizontalTitleGap: 0.0,
                                          visualDensity: const VisualDensity(
                                              horizontal: 0, vertical: -4),
                                          leading: const Icon(
                                              Ionicons.location_outline),
                                          title: Text(doc!['address']),
                                        ),
                                        ListTile(
                                          horizontalTitleGap: 0.0,
                                          visualDensity: const VisualDensity(
                                              horizontal: 0, vertical: -4),
                                          leading: const Icon(
                                              Ionicons.person_outline),
                                          title: Text(doc['name']),
                                        ),
                                        ListTile(
                                          horizontalTitleGap: 0.0,
                                          visualDensity: const VisualDensity(
                                              horizontal: 0, vertical: -4),
                                          leading:
                                              const Icon(Ionicons.call_outline),
                                          title: Text(doc['phoneNumber']),
                                        ),
                                        const SizedBox(
                                          height: 10.0,
                                        ),
                                        TextField(
                                          controller: deliveryNoteController,
                                          decoration: InputDecoration(
                                            hintText: 'Delivery note',
                                            enabledBorder: OutlineInputBorder(
                                              borderRadius:
                                                  BorderRadius.circular(8.0),
                                              borderSide: BorderSide(
                                                color: Colors.grey.shade400,
                                                width: 1.6,
                                              ),
                                            ),
                                            focusedBorder: OutlineInputBorder(
                                              borderRadius:
                                                  BorderRadius.circular(8.0),
                                              borderSide: BorderSide(
                                                color: Colors
                                                    .lightBlueAccent.shade700,
                                                width: 1.6,
                                              ),
                                            ),
                                          ),
                                        ),
                                        const SizedBox(
                                          height: 12.0,
                                        ),
                                      ],
                                    ),
                                    const Divider(
                                      thickness: 1.2,
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.all(15.0),
                                      child: Row(
                                        mainAxisAlignment:
                                            MainAxisAlignment.spaceBetween,
                                        children: [
                                          const Text(
                                            'Total Due',
                                            style: TextStyle(fontSize: 18),
                                          ),
                                          Text(
                                            'R${cart.totalAmount.toStringAsFixed(2)}',
                                            style: const TextStyle(
                                                fontSize: 22,
                                                letterSpacing: 0.5,
                                                fontWeight: FontWeight.bold),
                                          ),
                                        ],
                                      ),
                                    ),
                                    ElevatedButton(
                                      child: const Center(
                                        child: Padding(
                                          padding: EdgeInsets.symmetric(
                                              vertical: 15.0),
                                          child: Text(
                                            'Process Order',
                                            style: TextStyle(
                                              color: Colors.white,
                                            ),
                                          ),
                                        ),
                                      ),
                                      onPressed: () async {
                                        try {
                                          setState(() {
                                            isLoading = true;
                                          });
                                          await FirebaseFirestore.instance
                                              .collection('orders')
                                              .add({
                                            'date': DateTime.now(),
                                            'order': cart.items.values
                                                .map((prod) =>
                                                    '${prod.title}, ${prod.quantity}')
                                                .join(";")
                                                .toString(),
                                            'total': cart.totalAmount
                                                .toStringAsFixed(2),
                                          });
                                          Navigator.of(context)
                                              .pushReplacementNamed(
                                                  OrderSuccess.routeName);

                                          setState(() {
                                            isLoading = false;
                                          });

                                          cart.clearCart();
                                        } on FirebaseException catch (e) {
                                          print(e.toString());
                                          setState(() {
                                            isLoading = false;
                                          });
                                        }
                                      },
                                    ),
                                    const SizedBox(
                                      height: 20.0,
                                    ),
                                  ],
                                );
                              }),
                        ],
                      ),
                    ),
                  ),
          );
  }
}

【问题讨论】:

    标签: flutter dart google-cloud-firestore dart-null-safety


    【解决方案1】:

    空检查运算符是!,用于告诉 Dart 你确定前面的变量不为空。如果你错了(它是空的)你会得到这个错误。您的代码中有两个地方可能会出现此错误。

    在您的代码中,您有 final user = FirebaseAuth.instance.currentUser 并且它不是给定的,这不是空值,但是您在语句 .doc(user!.uid) 中使用空值检查运算符,如果 user 为空值,它将引发错误。

    同样,您使用DocumentSnapshot? doc = snapshot.data 设置变量doc(显然是可以为空的变量)并在title: Text(doc!['address']) 中使用空检查运算符,这也可能产生此错误。

    如果您的变量可以为空,那么您必须使用if... then 构造或使用可识别空的运算符(如???)来检查这种可能性。只有当您可以静态地证明可空变量永远在代码的某个点为空时,您才能放弃该检查并使用空检查运算符!

    【讨论】:

    • 感谢@Bram,我已将所有空检查运算符替换为可识别空值的运算符。但是我仍然遇到同样的错误
    • 如果错误确实发生在Navigator.of(context)... 语句中(如您的屏幕截图所示),那么您可能没有在小部件上方正确设置 MaterialApp(导航器需要一个 Router 和一个 @ 987654334@ 由MaterialAppWidgetsApp 创建)。
    • 我刚刚确保我的所有路由都已正确配置。奇怪的是,当我删除 isLoading 时?脚手架周围的 LoadingSpinner 条件。可能是什么问题? @布拉姆
    • 我怀疑这是因为没有脚手架(当 isLoading 为 true 时)路由器和导航器设置不正确。
    • @Bram 您的回答和您的 cmets 都没有提供任何价值,而不是误导提问者。
    猜你喜欢
    • 2021-10-19
    • 2021-08-19
    • 2021-07-22
    • 1970-01-01
    • 2022-10-19
    • 1970-01-01
    • 2021-09-09
    • 2021-11-18
    相关资源
    最近更新 更多