从Firebase获取数据至折线图对象列表失败的问题排查
问题:Firebase Realtime Database数据无法加载到折线图列表
我尝试从Firebase Realtime Database获取数据并映射到alldataSensor对象列表,用于SfCartesianChart折线图展示,但多次尝试后仍无法成功获取数据。
数据库结构说明
data节点下包含多个子节点,每个子节点包含以下字段:
Ts:时间戳(毫秒)EC:传感器EC值PH:传感器PH值RTD:传感器RTD值humidity:湿度值temperature:温度值
现有代码
数据模型与Firebase数据获取代码
class alldataSensor { DateTime timeStamp; double sensorEc; double sensorPh; double sensorRtd; double humidity; double temperature; alldataSensor( {required this.timeStamp, required this.temperature, required this.humidity, required this.sensorRtd, required this.sensorPh, required this.sensorEc}); factory alldataSensor.fromMap(Map<dynamic, dynamic> map) { return alldataSensor( timeStamp: DateTime.fromMillisecondsSinceEpoch(map['Ts']), sensorEc: map['EC'] as double, sensorPh: map['PH'] as double, sensorRtd: map['RTD'] as double, humidity: map['humidity'] as double , temperature: map['temperature'] as double, ); } } Future<List<alldataSensor>> getallDataSensor() async { DatabaseReference allDataSensor = FirebaseDatabase.instance.ref().child('data'); print(allDataSensor); // 调试用,查看是否返回数据 List<alldataSensor> needs = []; allDataSensor.onChildAdded.listen((event) { DataSnapshot dataSnapshot =event.snapshot; final Map<DateTime, dynamic> values = dataSnapshot.value as Map<DateTime, dynamic>; values.forEach((key, value) { needs.add(value); }); }); return needs; }
折线图调用列表代码
List<alldataSensor> _list = []; @override void initState() { super.initState(); _setupNeeds(); } _setupNeeds() async { List<alldataSensor> needs = await getallDataSensor(); setState(() { _list = needs; }); } Widget build(BuildContext context) { return SfCartesianChart( zoomPanBehavior: ZoomPanBehavior( enablePanning: true, enablePinching: true, enableDoubleTapZooming: true, enableMouseWheelZooming: true, maximumZoomLevel: 0.5, ), plotAreaBorderWidth: 0, primaryXAxis: DateTimeAxis( intervalType: DateTimeIntervalType.days, dateFormat: DateFormat.yMMMd(), interval: 1, majorGridLines: const MajorGridLines(width: 0), ), primaryYAxis: NumericAxis( axisLine: const AxisLine(width: 0), majorTickLines: const MajorTickLines(width: 0), ), legend: const Legend( isVisible: true, position: LegendPosition.bottom, ), series: <LineSeries<dynamic, DateTime>>[ LineSeries<alldataSensor, DateTime>( name: 'EC', legendIconType: LegendIconType.circle, dataSource: _list, xValueMapper: (alldataSensor data, _) => data.timeStamp, yValueMapper: (alldataSensor data, _) => data.sensorEc, onRendererCreated: (ChartSeriesController controller) { seriesController = controller; }, ), LineSeries<alldataSensor, DateTime>( name: 'pH', legendIconType: LegendIconType.circle, dataSource: _list, xValueMapper: (alldataSensor data, _) => data.timeStamp, yValueMapper: (alldataSensor data, _) => data.sensorPh, onRendererCreated: (ChartSeriesController controller) { seriesController = controller; }, ), ], loadMoreIndicatorBuilder: (BuildContext context, ChartSwipeDirection direction) { if (direction == ChartSwipeDirection.end) { getallDataSensor(); return SizedBox.fromSize(size: Size.zero); // 替换为此代码 } else { return SizedBox.fromSize(size: Size.zero); } }, ); }
问题分析与修复方案
1. Firebase数据获取逻辑错误
getallDataSensor函数中使用onChildAdded监听流,但函数在监听触发前就返回了空列表。应该使用get()方法一次性获取所有数据快照,确保数据加载完成后再返回列表。
2. 数据解析错误
Firebase返回的子节点键是字符串类型,且每个子节点的value是包含字段的Map,直接将dataSnapshot.value转为Map<DateTime, dynamic>会报错,需要将每个子节点的value通过fromMap工厂方法转换为alldataSensor对象。
3. 类型转换异常
Firebase返回的数字可能是int类型,直接强制转为double会抛出异常,需要用(num).toDouble()统一处理。
修复后的代码
数据模型的fromMap方法
factory alldataSensor.fromMap(Map<dynamic, dynamic> map) { return alldataSensor( timeStamp: DateTime.fromMillisecondsSinceEpoch(map['Ts']), sensorEc: (map['EC'] as num).toDouble(), sensorPh: (map['PH'] as num).toDouble(), sensorRtd: (map['RTD'] as num).toDouble(), humidity: (map['humidity'] as num).toDouble(), temperature: (map['temperature'] as num).toDouble(), ); }
Firebase数据获取函数
Future<List<alldataSensor>> getallDataSensor() async { DatabaseReference allDataSensor = FirebaseDatabase.instance.ref().child('data'); DataSnapshot snapshot = await allDataSensor.get(); List<alldataSensor> needs = []; if (snapshot.exists) { Map<String, dynamic> values = snapshot.value as Map<String, dynamic>; values.forEach((key, value) { needs.add(alldataSensor.fromMap(value)); }); } return needs; }
数据加载函数(增加错误处理)
_setupNeeds() async { try { List<alldataSensor> needs = await getallDataSensor(); setState(() { _list = needs; }); } catch (e) { print('获取数据失败: $e'); } }
折线图加载更多逻辑(更新状态)
loadMoreIndicatorBuilder: (BuildContext context, ChartSwipeDirection direction) { if (direction == ChartSwipeDirection.end) { _setupNeeds(); // 调用已有的加载方法更新数据 return SizedBox.fromSize(size: Size.zero); } else { return SizedBox.fromSize(size: Size.zero); } },
内容的提问来源于stack exchange,提问作者Erick Mahardika
相关产品推荐
相关产品推荐

