Flutter项目使用Syncfusion渲染JSON图表无报错却无法正常显示
Syncfusion Flutter 图表Release构建后不渲染排查方案
先明确你之前的两个判断的偏差:
- 数据量过大的诱因可以排除,你已经验证缩减数据量后问题依旧存在
- 数值幅度过小不会导致Syncfusion图表完全不渲染,该判断和实际组件逻辑不符,你的问题核心出在代码运行逻辑上,和数值范围没有直接关系
核心问题定位
- 全局列表重复累加导致数据源异常
你把t、ampA、ampB、ampC定义为State类的全局成员变量,在FutureBuilder的回调里直接向这些列表追加数据,全程没有做清空操作。加上initState已经调用过一次fetchEQData,FutureBuilder又会重复触发数据请求,会导致列表内重复塞入多份相同数据,甚至出现数据错位。在Release构建模式下,这类数据错位引发的解析异常会被直接静默处理,不会抛出可见报错,最终导致数据源为空或逻辑混乱,图表完全渲染失败。 - 类型解析逻辑与实际数据不匹配
你在Y值映射逻辑里用的是int.parse处理振幅值,但实际业务里的振幅是0.7、-0.6这类带小数的字符串,int.parse遇到带小数点的字符串会直接触发格式异常。这类异常在Debug模式下可能被框架的异常捕获层拦截,不会弹出明显提示,但会直接中断图表的绘制流程,最终页面只显示空的卡片容器。 - 图表系列类型与业务场景不匹配
你使用的是StackedLineSeries(堆叠折线系列),这类系列的设计逻辑是把每个数据点的多个Y值从0基线开始逐层累加,最终计算出每个点的实际绘制位置。如果你的业务数据是带正负的独立振幅值,堆叠计算后的位置会完全错乱,甚至可能所有计算后的绘制点都落在坐标轴可视范围外,视觉上就是完全空白的图表。 - FutureBuilder逻辑冗余触发重复请求
你在initState里调用了fetchEQData,但没有把这个请求的返回Future赋值给FutureBuilder的future参数,等于每次页面重建,FutureBuilder都会重新发起一次新的数据请求,和上面提到的列表累加问题叠加,会进一步放大数据异常的概率。
可落地的修复步骤
- 重构数据列表的作用域:把所有临时存储的列表从State全局成员变量移到
FutureBuilder的回调内部定义,每次回调执行时重新初始化列表,从根源上避免重复累加数据的问题;同时把fetchEQData的返回Future存为类的成员变量,在initState里初始化一次,供FutureBuilder使用,避免重复发起网络请求。 - 修正数据解析逻辑:把Y值映射里的int.parse替换为double.parse,匹配实际的小数字符串数据,避免格式解析异常。
- 匹配适配的图表系列类型:如果业务目标是展示三个独立的振幅序列,把StackedLineSeries替换为普通的
LineSeries即可;如果确实需要堆叠展示效果,保留堆叠系列的同时,需要调整基线逻辑适配带正负值的场景。 - 兜底配置坐标轴范围:如果排查后仍有可视区域异常,可以在
SfCartesianChart里手动配置primaryXAxis、primaryYAxis的最小值、最大值,避免自动范围计算因为异常数据出错,导致可视区域内没有任何可绘制的内容。
核心修改代码参考
// State类内部新增成员变量,存储单次请求的Future late Future<List<dynamic>> _eqDataFuture; @override void initState() { _eqDataFuture = fetchEQData(); super.initState(); } // build方法里的核心修改 Container( child: Center( child: FutureBuilder( future: _eqDataFuture, builder: (context, snapshot) { if (snapshot.hasData) { // 临时列表移到回调内部,每次重建时重新初始化 List<String> t = []; List<String> ampA = []; List<String> ampB = []; List<String> ampC = []; const stationID = '4853'; for (int i = 0; i < snapshot.data.length; i++) { if (snapshot.data[i].stationId == stationID) { t.add(snapshot.data[i].recordLength); ampA.add(snapshot.data[i].amplitudemaxa); ampB.add(snapshot.data[i].amplitudemaxb); ampC.add(snapshot.data[i].amplitudemaxc); } } return Card( child: SfCartesianChart( series: <ChartSeries>[ LineSeries<EqAmpData, double>( dataSource: getColumnData(t, ampA, ampB, ampC), dashArray: const <double>[5,5], xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x), yValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.y1), ), LineSeries<EqAmpData, double>( dataSource: getColumnData(t, ampA, ampB, ampC), dashArray: const <double>[5,5], xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x), yValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.y2), ), LineSeries<EqAmpData, double>( dataSource: getColumnData(t, ampA, ampB, ampC), dashArray: const <double>[5,5], xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x), yValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.y3), ), ] ) ); } return const CircularProgressIndicator(); }, ), ), )
内容的提问来源于stack exchange,提问作者googlesnet
相关产品推荐
相关产品推荐

