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

如何在Flutter Syncfusion Flutter Charts中展示JSON数据?解决参数类型不匹配错误

问题分析与解决方案

首先看你遇到的类型错误:The argument type 'String Function(SensorData, int, dynamic)' can't be assigned to the parameter type 'String Function(SensorData, int)',原因很直接——你给xValueMapper和yValueMapper传的回调函数参数数量不对。Syncfusion的这两个映射函数只接受两个参数:数据对象本身和索引,但你写了三个参数(SensorData, sensors, _),而且参数命名也搞混了(第一个参数是类型,没给变量名,第二个变量名sensors其实应该是数据对象)。

除了这个类型错误,你的代码还有几个关键问题需要修正,才能正确从API获取数据并渲染图表:


1. 修正X/Y值映射函数的签名

把xValueMapper和yValueMapper改成正确的参数结构,同时注意X轴是CategoryAxis,需要传入字符串类型的时间,所以要把DateTime转成字符串:

xValueMapper: (SensorData data, int index) => data.timeStamp.toString(),
yValueMapper: (SensorData data, int index) => data.sensorValue,

2. 修复API数据获取与解析逻辑

你的loadSensorData函数完全没有调用fetchUsers来获取API数据,而且直接用json.decode(toString())是无效的。另外,Thingspeak的API返回结构是包含feeds数组的对象,你需要正确解析这个数组,同时处理字段名不匹配的问题:

  • Thingspeak里的时间字段是created_at,不是timeStamp
  • 湿度值字段是field1,不是SensorValue
  • 接口返回的field1是字符串,需要转成int类型

修正后的loadSensorData和fetchUsers:

Future loadSensorData() async {
  try {
    final responseBody = await fetchUsers();
    final jsonResponse = json.decode(responseBody);
    // 从API返回的feeds数组中解析数据
    setState(() {
      chartData = (jsonResponse['feeds'] as List)
          .map((feed) => SensorData.fromJson(feed))
          .toList();
    });
  } catch (e) {
    print('加载数据出错: $e');
  }
}

Future<String> fetchUsers() async {
  var url = Uri.parse('https://api.thingspeak.com/channels/960293/fields/1.json');
  http.Response response = await http.get(url);
  // 检查响应状态码,确保请求成功
  if (response.statusCode == 200) {
    return response.body;
  } else {
    throw Exception('请求API失败,状态码: ${response.statusCode}');
  }
}

3. 修正SensorData的fromJson工厂方法

根据Thingspeak的字段名调整解析逻辑,并处理类型转换:

class SensorData {
  SensorData({
    required this.timeStamp,
    required this.sensorValue,
  });

  DateTime timeStamp;
  int sensorValue;

  factory SensorData.fromJson(Map<String, dynamic> json) {
    return SensorData(
      // 把字符串时间转成DateTime
      timeStamp: DateTime.parse(json['created_at']),
      // 把字符串值转成int,注意处理可能的null值
      sensorValue: int.parse(json['field1'] ?? '0'),
    );
  }
}

完整修正后的代码

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:http/http.dart' as http;

class LineChartHum extends StatefulWidget {
  @override
  _LineChartHumState createState() => _LineChartHumState();
}

class _LineChartHumState extends State<LineChartHum> {
  List<SensorData> chartData = [];

  @override
  void initState() {
    super.initState();
    loadSensorData();
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Container(
              margin: EdgeInsets.all(16),
              height: 300,
              child: SfCartesianChart(
                zoomPanBehavior: ZoomPanBehavior(
                  enableDoubleTapZooming: true,
                  enablePanning: true,
                  enableSelectionZooming: true,
                  enableMouseWheelZooming: true,
                ),
                primaryXAxis: CategoryAxis(
                  // 可以设置标签旋转,避免重叠
                  labelRotation: 45,
                ),
                title: ChartTitle(text: 'Humidity Sensor'),
                tooltipBehavior: TooltipBehavior(enable: true),
                series: <LineSeries<SensorData, String>>[
                  LineSeries<SensorData, String>(
                    dataSource: chartData,
                    xValueMapper: (SensorData data, int index) => data.timeStamp.toString(),
                    yValueMapper: (SensorData data, int index) => data.sensorValue,
                    // 可选:添加数据点标记
                    markerSettings: MarkerSettings(isVisible: true),
                  )
                ]))
        ],
      ),
    );
  }

  Future loadSensorData() async {
    try {
      final responseBody = await fetchUsers();
      final jsonResponse = json.decode(responseBody);
      setState(() {
        chartData = (jsonResponse['feeds'] as List)
            .map((feed) => SensorData.fromJson(feed))
            .toList();
      });
    } catch (e) {
      print('加载数据出错: $e');
    }
  }
}

Future<String> fetchUsers() async {
  var url = Uri.parse('https://api.thingspeak.com/channels/960293/fields/1.json');
  http.Response response = await http.get(url);
  if (response.statusCode == 200) {
    return response.body;
  } else {
    throw Exception('请求API失败,状态码: ${response.statusCode}');
  }
}

class SensorData {
  SensorData({
    required this.timeStamp,
    required this.sensorValue,
  });

  DateTime timeStamp;
  int sensorValue;

  factory SensorData.fromJson(Map<String, dynamic> json) {
    return SensorData(
      timeStamp: DateTime.parse(json['created_at']),
      sensorValue: int.parse(json['field1'] ?? '0'),
    );
  }
}

这样修改后,你的图表应该能正确加载并显示Thingspeak的湿度数据了。另外我还加了一些优化,比如X轴标签旋转、数据点标记,以及错误捕获逻辑,让代码更健壮。

内容的提问来源于stack exchange,提问作者isofttechn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 14:24:05