我试图绘制一些实时数据,"实时"这意味着< 10毫秒数据,理想情况下尽可能低。我已经能够让Android快速获取和处理数据,但ACE看起来并不是为了实时使用而设计的。最初的症状是,垃圾收集器就像没有明天一样开始并完全杀死应用程序。我在"滑动窗口上可视化数据"时尚,所以我不希望ACE实时绘制数万分之一的点数。 我已经看了一下它,onDraw for XYChart肯定会分配非常大的情况,它看起来很方便,可能会让代码更具可读性,但并不是真正需要的。 这甚至可能比以前更糟,所以它可能还没有被注意到。我看到问题#225的bugfix解决了并发问题的变化:
return mXY.subMap(start, stop);
有:
return new TreeMap<Double, Double>(mXY.subMap(start, stop));
这会产生巨大的分配(仍然由原始子映射支持),当onDraw正在进行时排队更新可能会更好,并且稍后在原子更新或该行上的某些事情处理它们以避免并发问题。
真正的遗憾在这里 ACE肯定能够满足我的需求。它可以完美地完成我在硬件上所需要的东西,但由于它在重绘Android上的分配如此严重,因为它对GC很疯狂。它很快就开始分配,而GC正在运行,所以它必须等待,我的应用程序开始看起来像一个定格动画电影。
真正的问题是:期望能够用ACE实时重绘(平板电脑应用程序)4或6个线性图表是否合理(或者是200毫秒刷新率),还是仅仅没有为这种滥用做好准备? 如果答案是否定的。你推荐的其他选择吗?
编辑20130109: 对于小型数据集,版本471改进了很多东西。 2.000点/ 4个图表/ 100毫秒刷新率是可行和平滑的。日志仍然可以看到&#34; GC_CONCURRENT被释放&#34;喜欢疯狂(大约10 /秒),但没有&#34; WAIT_FOR_CONCURRENT_GC被阻止&#34;哪些是使你的应用程序停止运动的showstoppers。 在3.000点/ 1图表/ 100毫秒时,它显然不平滑。我们再次遭遇雪崩&#34; WAIT_FOR_CONCURRENT_GC封锁&#34;在logcat和口吃的应用程序。再次看起来我们没有速度问题,只有内存管理问题。
看起来我可能会要求ACE做魔术,但是在重构我的所有代码以检索和存储1KHz的遥测数据之后我就碰到了这堵墙。一旦我终于看到我的应用程序检索并存储了所有这些实时而没有触发GC,我在试图绘制时用ACE拉我的头发:)
答案 0 :(得分:2)
首先感谢你提出的重要问题。你绝对是在onDraw()
方法下完成的巨大内存分配。我修复了它并检查了SVN中的代码。我还在onDraw()
方法中添加了一个synchronized块,例如在重新绘制期间向数据集添加新数据时,它有望不会抛出ConcurrentModificationException
。
请检查SVN的代码并执行ant dist以构建新的AChartEngine jar文件并将其嵌入到您的应用程序中。请参阅说明here。
回答你的问题:AChartEngine绝对可以用于动态制图。您报告的问题是显示阻止,但现在应该修复。我用它写了动态图表。但是,您需要确保不向数据集添加100000个数据值。可以从数据集中删除旧数据以获得性能。
如果它们的最高点数为1000,那么绘制5个左右的折线图是绝对合理的。
答案 1 :(得分:0)
在优化我的应用程序上的所有其他内容后,我仍然无法根据我对“实时”的理解进行绘制。 这个库很棒,而且非常快,但是每个onDraw分配内存的方式不可避免地会引发垃圾收集的雪崩,这会与自己的分配相冲突,因此android会暂时冻结你的应用程序,造成与“实时”图形完全不兼容的口吃。这里的“口吃”范围可以是50到250毫秒(是毫秒),但这足以杀死实时应用程序。
AChartengine只允许你创建“动态”图表,只要你不要求它们是“实时”(10帧/秒,(<100毫秒刷新率)或你称之为“平滑”的图形)。
如果有人需要有关核心问题的更多信息,或者为什么我说库足够快但内存分配模式最终会导致性能问题,请查看Google I/O 2009 - Writing Real-Time Games for Android
答案 2 :(得分: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%的时间在删除功能上,因为我删除了滚出视图的点。原因是当你删除最小|最大点时,ACE调用InitRange,迭代每个点以重新计算它在内部使用的那些最小/最大点。由于我每秒处理1000个遥测帧并且有一个小视口(由ACE内存分配策略强制),我在删除功能上经常达到最小/最大点数。 我创建了一个新方法,用于删除系列的第一个点,通常会在添加一个点时调用该点,使得一个点滚出视口。如果你的点按键值(经典日期时间序列)排序,那么我们可以调整mMinX,这样视口看起来仍然很好,并且非常快。 我们无法使用当前的ACE实现快速更新minY或maxY(不是我调查它),但如果您设置了适当的初始范围,则可能不需要它。事实上,我使用额外的信息不时手动调整范围,因为我知道我正在绘制的内容以及不同时间点的正常范围。
所以,对于其他人来说这可能已经足够了,但我坚持认为,对于任何严肃的实时图表,ACE仍然需要内存分配重构。