9

我正在尝试绘制一些实时数据,这里的“实时”意味着 < 10 毫秒的数据,理想情况下尽可能低。我已经能够让 Android 如此快速地获取和处理数据,但 ACE 看起来并不是为实时使用而设计的。第一个症状是垃圾收集器像没有明天一样启动并完全杀死应用程序。我正在以“滑动窗口”方式可视化数据,因此我并不期望 ACE 实时绘制千分之几的点。我已经看过它,并且 XYChart 的 onDraw 在看起来很方便并且可能使代码更具可读性但并不是真正需要的情况下肯定会分配非常多的。这甚至可能比以前更糟,所以它可能还没有被注意到。

return mXY.subMap(start, stop);

为了:

return new TreeMap<Double, Double>(mXY.subMap(start, stop));

这会创建巨大的分配(尽管仍然由原始 subMap 支持),当 onDraw 正在进行时将更新排队并稍后在原子更新或该行上的某些东西上处理它们可能会更好,以避免并发问题。

真正的遗憾ACE 的速度确实足够满足我的需要。它可以完美地在我的硬件上完成我需要的工作,但是由于它在重绘上分配了如此多的资源,因此 Android 对 GC 感到很疯狂。它很快就会在 GC 运行时开始分配,所以它必须等待,我的应用程序开始看起来像定格动画电影。

但真正的问题是:期望能够使用 ACE 实时(低于 200 毫秒的刷新率)重新绘制 4 或 6 个折线图(平板电脑应用程序)是否合理,或者它根本没有为这种滥用做好准备?如果答案是否定的。您还有其他选择吗?

编辑 20130109: 修订版 471 对小型数据集进行了相当大的改进。2.000 点 / 4 个图表 / 100 毫秒刷新率是可行且流畅的。日志仍然会疯狂地看到“GC_CONCURRENT freed”(大约 10/秒),但没有“WAIT_FOR_CONCURRENT_GC blocked”,这是让您的应用停止运动的表现。在 3.000 点/1 个图表/100 毫秒时,它显然平滑。我们再次在 logcat 和口吃应用程序上遇到“WAIT_FOR_CONCURRENT_GC 被阻止”的雪崩。再次看起来我们没有速度问题,只有内存管理问题。

看起来我可能会要求 ACE 变魔术,但在重构所有代码以检索和存储 1KHz 的遥测数据后,我碰上了这堵墙。一旦我终于看到我的应用程序在完全不触发 GC 的情况下实时检索和存储所有这些内容,我在尝试绘制图表时用 ACE 拉扯我的头发:)

4

3 回答 3

2

首先感谢您提出的好问题和您提出的观点。对于在该方法下完成的巨大内存分配,您绝对是正确的onDraw()。我修复了这个问题并签入了 SVN 中的代码。我还在方法中添加了一个同步块,例如在重绘期间向数据集添加新数据时onDraw()希望它不会抛出。ConcurrentModificationException

请从 SVN 签出代码并执行 ant dist 以构建新的 AChartEngine jar 文件并将其嵌入到您的应用程序中。请在此处查看说明。

回答您的问题:AChartEngine 绝对可以用于动态图表。您报告的问题是一个阻碍,但现在应该修复它。我已经使用它编写了动态图表。但是,您需要确保不会向数据集添加 100000 个数据值。可以从数据集中删除旧数据以获得性能。

如果它们有多达几千个点,绘制 5 个左右的折线图绝对是合理的。

于 2013-01-08T11:23:37.720 回答
0

好的,所以在寻找另一个图形库一段时间后,我发现没有什么足够好的 :) 这让我再次研究 ACE,最后我做了一个小补丁,虽然远非理想,但它使它对我“可用”。

在 XYSeries.java 我添加了一个新方法:

/**
* Removes the first value from the series.
* Useful for sliding, realtime graphs where a standard remove takes up too much time.
* It assumes data is sorted on the key value (X component).
*/
public synchronized void removeFirst() {
  mXY.removeByIndex(0);
  mMinX = mXY.getXByIndex(0);
}    

我发现除了内存问题之外,还有一些高速帧速率下的实际速度问题。我在删除功能上花费了大约 90% 的时间,因为我删除了滚动到视野之外的点。原因是当您删除一个 min|max 点时,ACE 调用 InitRange 迭代每个点以重新计算它在内部使用的那些 min/max 点。由于我每秒处理 1000 个遥测帧并且视口很小(由 ACE 内存分配策略强制),因此我经常在删除功能上达到最小/最大点。我创建了一种新方法,用于删除系列的第一个点,通常在您添加一个使该点滚动出视口的点后立即调用该方法。如果您的点按键值排序(经典的 dateTime 系列),那么我们可以调整 mminX,这样视口仍然看起来不错并且做得非常快。我们不能使用当前的 ACE 实现快速更新 minY 或 maxY(虽然我没有研究过),但是如果您设置了适当的初始范围,则可能不需要它。事实上,我不时使用我拥有的额外信息手动调整范围,因为我知道我在绘制什么以及不同时间点的正常范围是多少。

因此,这对其他人来说可能已经足够了,但我坚持认为,对于任何严肃的实时图形,ACE 上仍然需要内存分配重构。

于 2013-01-24T12:52:48.383 回答
0

经过大力优化我的应用程序上的其他所有内容后,我仍然无法让它以我所理解的“实时”绘图。该库很棒,而且速度非常快,但是每个 onDraw 分配内存的方式不可避免地会触发大量垃圾收集,这会与其自己的分配发生冲突,因此 android 会暂时冻结您的应用程序,从而导致与“实时”图形完全不兼容的卡顿。这里的“口吃”可以在 50-250 毫秒(是毫秒)之间,但这足以杀死一个实时应用程序。

只要您不要求它们是“实时的”(10 帧/秒,(<100ms 刷新率)或您所谓的“平滑”),AChartengine 将允许您创建“动态”图表。

如果有人需要更多关于核心问题的信息,或者为什么我说库足够快但内存分配模式最终导致性能问题,请查看Google I/O 2009 - Writing Real-Time Games for Android

于 2013-01-16T22:18:36.870 回答