Flutter调用Firebase Firestore报_throw错误的原因及解决方法
问题排查:Flutter从Firebase Firestore通过Document ID获取数据报错
我是Flutter、Firebase及编程新手,尝试通过Document ID从Firebase Firestore的sensor集合获取数据,赋值给变量后在卡片中展示,但出现错误信息:external static Never _throw(Object error, StackTrace stackTrace);。以下是代码和完整错误信息,求帮忙排查原因并解决。
使用的代码
// ignore_for_file: prefer_const_constructors import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:moncey2/pages/sensor_details.dart'; class SensorCard extends StatefulWidget { const SensorCard({required this.sensorId, super.key}); final String sensorId; @override State<SensorCard> createState() => _SensorCardState(); } class _SensorCardState extends State<SensorCard> { String temperature = ""; String location = ""; String nomDuCapteur = ""; @override void initState() { super.initState(); getDataFromFirebase(); } void getDataFromFirebase() { final firestoreInstance = FirebaseFirestore.instance; firestoreInstance .collection("sensor") .doc(widget.sensorId) .get() .then((documentSnapshot) { if (documentSnapshot.exists) { setState(() { temperature = documentSnapshot["current_temp"]; location = documentSnapshot["sensor_location"]; nomDuCapteur = documentSnapshot["sensor_name"]; }); } }); } @override Widget build(BuildContext context) { return Slidable( endActionPane: const ActionPane( motion: ScrollMotion(), children: [ SlidableAction( flex: 1, onPressed: null, backgroundColor: Colors.red, foregroundColor: Colors.white, icon: Icons.favorite, label: 'Favorites', ), ], ), child: ListTile( tileColor: Colors.white, isThreeLine: true, shape: RoundedRectangleBorder( side: BorderSide(width: 0.9), borderRadius: BorderRadius.circular(15), ), leading: CircleAvatar( backgroundColor: Colors.white, child: Icon( Icons.sensors, color: Colors.blue, ), ), title: Text( nomDuCapteur, textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 17, ), ), subtitle: Column( children: [ Text( location, ), ], ), trailing: Padding( padding: const EdgeInsets.fromLTRB(0, 15, 10, 0), child: Text(temperature, style: TextStyle(fontWeight: FontWeight.bold)), ), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (BuildContext context) => SensorDetails( alertHigh: '8', alertLow: '2', ), ), ); }, ), ); } }
错误信息
@patch @pragma("vm:external-name", "Error_throwWithStackTrace") external static Never _throw(Object error, StackTrace stackTrace);
排查与解决步骤
1. 先捕获真实错误信息
你看到的是Dart底层抛出错误的方法定义,不是真正的报错原因。必须给Firestore请求添加错误捕获,才能看到具体问题:
修改getDataFromFirebase方法,加入catch块:
void getDataFromFirebase() { final firestoreInstance = FirebaseFirestore.instance; firestoreInstance .collection("sensor") .doc(widget.sensorId) .get() .then((documentSnapshot) { if (documentSnapshot.exists) { setState(() { temperature = documentSnapshot["current_temp"].toString(); // 强制转字符串,避免类型不匹配 location = documentSnapshot["sensor_location"]; nomDuCapteur = documentSnapshot["sensor_name"]; }); } }).catchError((error, stackTrace) { print("Firestore请求错误: $error"); print("堆栈信息: $stackTrace"); }); }
添加后运行项目,查看控制台输出的真实错误,这是定位问题的核心。
2. 常见问题及处理
- 数据类型不匹配:如果Firestore中
current_temp是数字类型(int/double),直接赋值给String变量会报错,上面代码中添加的.toString()可以解决这个问题。 - Firestore权限限制:检查Firebase控制台的Firestore安全规则,确保允许读取
sensor集合。测试环境可以临时开放权限(上线后务必修改为基于用户认证的规则):rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /sensor/{document} { allow read, write: if true; } } } - Document ID无效:打印
widget.sensorId确认传入的ID是否正确,是否存在于Firestore的sensor集合中。 - Firebase初始化不全:确认项目已正确配置Firebase(google-services.json/GoogleService-Info.plist文件已添加,pubspec.yaml的Firebase依赖已正确安装)。
3. 代码优化方案(可选)
用FutureBuilder替代initState手动获取数据,更符合Flutter状态管理逻辑,还能处理加载、错误状态:
@override Widget build(BuildContext context) { return FutureBuilder<DocumentSnapshot>( future: FirebaseFirestore.instance.collection("sensor").doc(widget.sensorId).get(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); // 加载中显示转圈 } if (snapshot.hasError) { return Text("加载失败: ${snapshot.error}"); } if (!snapshot.hasData || !snapshot.data!.exists) { return Text("该传感器不存在"); } var data = snapshot.data!.data() as Map<String, dynamic>; String temperature = data["current_temp"].toString(); String location = data["sensor_location"]; String nomDuCapteur = data["sensor_name"]; // 原Slidable和ListTile代码直接复用 return Slidable( endActionPane: const ActionPane( motion: ScrollMotion(), children: [ SlidableAction( flex: 1, onPressed: null, backgroundColor: Colors.red, foregroundColor: Colors.white, icon: Icons.favorite, label: 'Favorites', ), ], ), child: ListTile( tileColor: Colors.white, isThreeLine: true, shape: RoundedRectangleBorder( side: BorderSide(width: 0.9), borderRadius: BorderRadius.circular(15), ), leading: CircleAvatar( backgroundColor: Colors.white, child: Icon( Icons.sensors, color: Colors.blue, ), ), title: Text( nomDuCapteur, textAlign: TextAlign.center, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 17, ), ), subtitle: Column( children: [Text(location)], ), trailing: Padding( padding: const EdgeInsets.fromLTRB(0, 15, 10, 0), child: Text(temperature, style: TextStyle(fontWeight: FontWeight.bold)), ), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (BuildContext context) => SensorDetails( alertHigh: '8', alertLow: '2', ), ), ); }, ), ); }, ); }
内容的提问来源于stack exchange,提问作者MoncefBnk
相关产品推荐
相关产品推荐

