【问题标题】:Is achartengine ready for realtime graphing?achartengine 准备好实时绘图了吗?
【发布时间】:2012-12-20 16:42:39
【问题描述】:

我正在尝试绘制一些实时数据,这里的“实时”意味着

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 拉扯头发:)

【问题讨论】:

  • 能否请您分享指向您的源代码或任何特定于在 Android 应用中绘制心电图的教程的链接。我试图达到同样的效果,但我无法理解如何绘制 X 轴;从心电图设备解析心电图数据后,我得到的是一个数字数组:0.74、0.732、..等

标签: android achartengine


【解决方案1】:

好的,所以在寻找另一个图形库后,我发现没有什么好 :) 这让我再次研究 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 上仍然需要内存分配重构。

【讨论】:

    【解决方案2】:

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

    AChartengine 将允许您创建“动态”图表,只要您不要求它们是“实时的”(10 帧/秒,(

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

    【讨论】:

      【解决方案3】:

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

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

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

      如果有 1000 多点,绘制 5 个左右的折线图绝对是合理的。

      【讨论】:

      • 我会检查一下,但我确实恢复了那个特定的问题,但仍然发现 GC 是一个问题。我使用 Eclipses 分配跟踪器更深入地研究了代码,并看到了许多其他关于 onDraw 分配的问题区域。我可以使用官方演示进行测试,因此如果您愿意研究它,我们可以查看相同的问题,但需要围绕对象工厂/池进行一些重构,以使 Ace 在 Android 上实时工作。你在 HoneyComb 中测试这个吗? GC 完全更改为并发 GC 算法,因此在以前的版本中可能不是问题。
      • 我对代码做了很大的重构,并在 SVN 中签入了东西。数据被复制和复制的地方减少了很多。您能否再次对其进行分析,并让我知道现在情况是否有所改善?
      • 你需要把10000点*4的图表全部显示在屏幕上吗?当不再出现在屏幕上时,您是否可以删除一些数据?
      • 当然可以。坏消息是我刚刚进行了第一次压力测试的那些数字。我现在已经看到它可以顺利进行多高,看起来这几乎是我的初始测试。它在 3.000 点 / 1 个单张图表 / 100 毫秒刷新率时出现卡顿。刚刚编辑的结果。重构是一个真正关注速度而不是内存的优化,速度很好,当我们需要实时刷新时间时内存不是这样。
      猜你喜欢
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-14
      • 2015-11-08
      • 2017-12-23
      • 2016-07-17
      • 2017-01-07
      相关资源
      最近更新 更多