如何解决QR扫码功能中FutureBuilder内的空检查运算符异常?
问题
我正在开发一个QR扫码功能,当未识别到QR码时,通过else if语句显示等待状态:
else if (result == null) { return Column( children: [ const Text("Welcome!"), Text("Fee:${load["Fee"]}"), ], ); }
但添加FirebaseFirestore的FutureBuilder后,语句late Message data = Message.fromJson(jsonDecode((result!.code!)));会抛出「Null check operator used on a null value」异常,且异常指向该变量语句。希望解决该异常,同时保留else if实现的等待状态显示,完整代码如下:
Barcode? result; FutureBuilder<DocumentSnapshot>( future: FirebaseFirestore.instance .collection('Drivers') .doc(FirebaseAuth.instance.currentUser?.email) .get(), builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) { if (snapshot.hasError) { return Text("Something went wrong"); } if (snapshot.hasData && !snapshot.data!.exists) { return Text("Document does not exist"); } if (snapshot.connectionState == ConnectionState.done) { Map<String, dynamic> load = snapshot.data!.data() as Map<String, dynamic>; late Message data = Message.fromJson(jsonDecode((result!.code!))); //Null check Operator Runtime Error unless no Builder there. int total = data.price * data.passenger; return Column( children: [ Row(children: [Text(load["name"]),],), Container( height: 100, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Container(child: LayoutBuilder(builder: (context, constraints) { if ((result != null) && (load["Fee"] == data.price)) { return FutureBuilder<DocumentSnapshot>( future: FirebaseFirestore.instance.collection('Users').doc(data.email).get(), builder:(context, snapshot) { if ((snapshot.hasError)||(snapshot.hasData && !snapshot.data!.exists)) { return const Text("Something went wrong, Try again"); } if (snapshot.connectionState == ConnectionState.done) { Map<String, dynamic> moneycheck = snapshot.data!.data() as Map<String, dynamic>; if (moneycheck['Balance'] >= total){ return Column( children: [ Text("Payment Made! \n ${DateTime.now().toString()}"), Text("Price: RM${data.price} per Person"), Text("Total: RM${data.totalprice}"), Text("Persons: ${data.passenger}"), ], ); } else if (moneycheck['Balance'] < total){ return Column( children: [ Text("Insufficient Balance"), Text("Balance: RM ${moneycheck['Balance']}"),Text("Price: RM${data.price} per Person"), Text("Total: RM${data.totalprice}"),Text("Persons: ${data.passenger}"), ], ); } } return const Text("Loading..."); }, ); } else if (result == null) { return Column( children: [ const Text("Welcome!"), Text("Fee:${load["Fee"]}"), ], ); } else if ((result != null) && (load["Fee"] != data.price)) { return Column( children: [ const Text("Invalid QR Code!"), Text("${data.price}"), Text("${data.totalprice}"),], ); } else { return const Column( children: [ Text("Unknown Error Occured"), ], ); } }) ) ], ), ), ], ); } return const Text("Loading"); }, )
解决方案
异常原因是Firebase的FutureBuilder完成后,无论result(扫码结果)是否为null,都会执行result!.code!的强制非空操作,直接触发空指针异常。解决思路是把data的初始化逻辑限制在result非空的分支内,避免空值访问:
- 移除全局的
late Message data声明,将其移到result != null的判断分支内部,确保只有扫码成功后才初始化data。 - 提前处理
result == null的情况,在LayoutBuilder的builder中优先判断result是否为空,提前返回等待状态,避免后续代码执行空值操作。 - 增加
result.code的空值校验,防止扫码结果的code字段为空。
修改后的完整代码:
Barcode? result; FutureBuilder<DocumentSnapshot>( future: FirebaseFirestore.instance .collection('Drivers') .doc(FirebaseAuth.instance.currentUser?.email) .get(), builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) { if (snapshot.hasError) { return Text("Something went wrong"); } if (snapshot.hasData && !snapshot.data!.exists) { return Text("Document does not exist"); } if (snapshot.connectionState == ConnectionState.done) { Map<String, dynamic> load = snapshot.data!.data() as Map<String, dynamic>; return Column( children: [ Row(children: [Text(load["name"]),],), Container( height: 100, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Container(child: LayoutBuilder(builder: (context, constraints) { // 优先处理未扫码状态 if (result == null) { return Column( children: [ const Text("Welcome!"), Text("Fee:${load["Fee"]}"), ], ); } // 处理扫码结果为空的情况 if (result?.code == null) { return const Text("Invalid QR Code: Empty content"); } // 安全初始化data Message data = Message.fromJson(jsonDecode(result!.code!)); int total = data.price * data.passenger; // 校验费用匹配 if (load["Fee"] == data.price) { return FutureBuilder<DocumentSnapshot>( future: FirebaseFirestore.instance.collection('Users').doc(data.email).get(), builder:(context, snapshot) { if ((snapshot.hasError)||(snapshot.hasData && !snapshot.data!.exists)) { return const Text("Something went wrong, Try again"); } if (snapshot.connectionState == ConnectionState.done) { Map<String, dynamic> moneycheck = snapshot.data!.data() as Map<String, dynamic>; if (moneycheck['Balance'] >= total){ return Column( children: [ Text("Payment Made! \n ${DateTime.now().toString()}"), Text("Price: RM${data.price} per Person"), Text("Total: RM${data.totalprice}"), Text("Persons: ${data.passenger}"), ], ); } else { return Column( children: [ Text("Insufficient Balance"), Text("Balance: RM ${moneycheck['Balance']}"), Text("Price: RM${data.price} per Person"), Text("Total: RM${data.totalprice}"), Text("Persons: ${data.passenger}"), ], ); } } return const Text("Loading..."); }, ); } else { return Column( children: [ const Text("Invalid QR Code!"), Text("${data.price}"), Text("${data.totalprice}"), ], ); } })) ], ), ), ], ); } return const Text("Loading"); }, )
内容的提问来源于stack exchange,提问作者Q40
相关产品推荐
相关产品推荐

