AnyChart折线图无法实时更新API数据,首次加载正常后续显旧数据
从你的代码来看,导致折线图无法更新、始终显示旧数据的核心问题有两个:
CustomDataEntry构造函数的逻辑错误
你在CustomDataEntry的构造方法里,把整个List<String> x直接转成字符串传给父类的ValueDataEntry,这会导致所有数据点的x轴标识都是同一个列表的字符串(比如[2023-01,2023-02]),而不是每个数据项对应的单个x轴标签。当你第二次请求新数据时,即使数据内容变化,x轴的标识没有差异,AnyChart无法识别这是新的数据集,因此依然显示旧数据。每次更新都重新创建完整图表,未正确处理旧状态
你每次调用anyChartGraphViewData时都重新创建Cartesian实例并设置给anyChartView,虽然理论上可行,但AnyChart的视图可能没有完全释放旧的图表绑定,再加上数据标识的错误,最终导致更新失效。
第一步:修复CustomDataEntry构造函数
每个CustomDataEntry对应单个数据点,应该传入当前循环的单个x轴标签,而不是整个列表:
private class CustomDataEntry extends ValueDataEntry { CustomDataEntry(String x, Number value1, Number value2) { // 父类第一个参数是单个x轴值 super(x, value1); setValue("value1", value1); setValue("value2", value2); } }
同时修改循环创建数据项的代码,传入单个x标签:
for (OpdIpdModel opdIpdModel : response.body().getOpdIpdComparison()) { String xLabel = opdIpdModel.getYear().shortValue() + "-" + opdIpdModel.getMonthString(); entries1.add(new CustomDataEntry(xLabel, opdIpdModel.getoPD(), opdIpdModel.getiPD())); }
第二步:优化图表更新逻辑(推荐)
不需要每次请求都重新创建完整的Cartesian图表,复用已有实例并仅更新数据集合,既高效又能避免视图绑定问题:
- 将图表核心对象改为类成员变量:
public class OpdIpdAnalysis extends AppCompatActivity implements NetworkReceiver.ConnectionChangeCallback { AnyChartView anyChartView; Set set1; Cartesian cartesian; Line series1; Line series2; // 新增类成员变量 // ... 其他原有代码 }
- 在
onCreate中初始化一次图表基础配置:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_opd_ipd_analysis); anyChartView = findViewById(R.id.anyChartLineChart); anyChartView.setProgressBar(myProgressBar); // 仅初始化一次图表基础配置 initChart(); } private void initChart() { cartesian = AnyChart.line(); cartesian.animation(true); cartesian.padding(5d, 10d, 1d, 5d); cartesian.crosshair().enabled(true); cartesian.crosshair() .yLabel(true) .yStroke((Stroke) null, null, null, (String) null, (String) null); cartesian.tooltip().positionMode(TooltipPositionMode.POINT); cartesian.title("MIS Report of comparing OPD and IPD data."); cartesian.xAxis(0).labels().padding(1d, 1d, 1d, 1d); cartesian.xAxis(0).labels().fontSize(8); cartesian.legend().enabled(true); cartesian.legend().fontSize(10d); cartesian.legend().padding(0d, 0d, 10d, 0d); cartesian.interactivity().hoverMode(HoverMode.BY_X); cartesian.xScroller(true); anyChartView.setZoomEnabled(true); // 初始化数据集和折线系列 set1 = Set.instantiate(); Mapping series1Mapping = set1.mapAs("{ x: 'x', value: 'value1' }"); Mapping series2Mapping = set1.mapAs("{ x: 'x', value: 'value2' }"); series1 = cartesian.line(series1Mapping); series1.name("OPD"); series1.hovered().markers().enabled(true); series1.hovered().markers() .type(MarkerType.CIRCLE) .size(5d); series1.tooltip() .position("right") .anchor(Anchor.LEFT_CENTER) .offsetX(0d) .offsetY(0d); series2 = cartesian.line(series2Mapping); series2.name("IPD"); series2.hovered().markers().enabled(true); series2.hovered().markers() .type(MarkerType.CIRCLE) .size(5d); series2.tooltip() .position("right") .anchor(Anchor.LEFT_CENTER) .offsetX(0d) .offsetY(0d); anyChartView.setChart(cartesian); }
- 修改
anyChartGraphViewData方法,仅更新数据集合:
private void anyChartGraphViewData(Response<OpdIpdModel.ModelResponse> response) { List<DataEntry> entries1 = new ArrayList<>(); if (response.body() != null) { for (OpdIpdModel opdIpdModel : response.body().getOpdIpdComparison()) { String xLabel = opdIpdModel.getYear().shortValue() + "-" + opdIpdModel.getMonthString(); entries1.add(new CustomDataEntry(xLabel, opdIpdModel.getoPD(), opdIpdModel.getiPD())); } } // 清空旧数据并设置新数据,强制图表重绘 set1.clear(); set1.data(entries1); cartesian.draw(); anyChartView.invalidate(); }
第三步:确保UI更新在主线程
Retrofit的onResponse回调默认在主线程执行,所以你的现有代码没问题,但如果后续有其他异步操作,要确保更新图表的代码在主线程:
runOnUiThread(() -> { anyChartGraphViewData(response); });
完成以上修改后,第二次请求新数据时,数据集的x轴标签会是正确的单个值,图表会识别到新数据并更新显示。如果仍有问题,可以尝试在设置新数据前调用anyChartView.clear()清空旧图表视图。
内容的提问来源于stack exchange,提问作者Aleef Faminn

