You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 22:45:43