使用Android自定义视图实时绘制图表

seb*_*123 7 android

我想在我的应用程序中使用实时绘图制作简单的线条图.我知道有很多不同的图书馆,但它们太大或没有正确的功能或许可证.

我的想法是制作自定义视图,只是扩展View类.使用OpenGL在这种情况下会像射击用佳能鸭子.我已经有了绘制静态数据的视图 - 首先我将所有数据放在float我的Plot对象的数组中,然后使用循环绘制类的onDraw()方法中的所有内容PlotView.

我还有一个线程可以为我的情节提供新数据.但现在的问题是如何在添加新数据时绘制它.首先想到的是简单地添加新点和绘图.添加另一个.但我不确定在100或1000点会发生什么.我正在添加新点,请求视图使自己无效,但仍然没有绘制一些点.在这种情况下,即使使用某个队列也可能很困难,因为onDraw()它将从头开始,因此队列元素的数量将增加.

你会推荐什么来达到这个目标?

Mar*_*nna 3

让我尝试更详细地描述一下这个问题。

  • 您已经有了一个可以在其上绘制点和线的表面,并且您知道如何使其看起来像您想要的样子。
  • 您有一个提供要绘制的点的数据源,并且该数据源会动态更改。
  • 您希望表面尽可能准确地反映传入的数据。

第一个问题是——你的情况慢怎么办?你知道你的延误是从哪里来的吗?首先,确定你有一个需要解决的问题;其次,确保你知道你的问题来自哪里。

假设您的问题在于您所暗示的数据大小。如何解决这个问题是一个复杂的问题。这取决于绘制图表的数据的属性——您可以假设哪些不变量等等。您已经讨论过将数据存储在 a 中float[],所以我假设您有固定数量的数据点,这些数据点的值会发生变化。我还假设“100 或 1000”的意思是“很多很多”,因为坦率地说,1000 个浮点数并不是很多数据。

当您要绘制一个非常大的数组时,您的性能限制最终将来自于数组的循环。然后,您的性能增强将减少循环的数组量。这就是数据属性发挥作用的地方。

减少重绘操作量的一种方法是保留一个“脏列表”,其作用类似于Queue<Int>. 每次数组中的单元格发生更改时,您都会将该数组索引排入队列,并将其标记为“脏”。每次您的绘制方法返回时,将脏列表中固定数量的条目出列,并仅更新与这些条目相对应的渲染图像块 - 您可能需要进行一些缩放和/或抗锯齿或因为有了这么多的数据点,您获得的数据可能比屏幕像素还要多。在任何给定帧更新中重绘的条目数量应受到所需帧速率的限制——您可以根据先前绘制操作花费的时间以及脏列表的深度的度量来使其自适应,以保持良好的帧率帧速率和可见数据年龄之间的平衡。

如果您尝试一次在屏幕上绘制所有数据,则此方法特别合适。如果您只查看一部分数据(例如在可滚动视图中),并且数组位置和窗口大小之间存在某种对应关系,那么您可以“窗口”数据 - 在每次绘制调用中,仅考虑屏幕上实际显示的数据子集。如果您还需要进行“缩放”操作,则可以混合使用这两种方法——这可能会变得复杂。

如果您的数据是窗口化的,使得每个数组元素中的值决定数据点是在屏幕上还是在屏幕外,请考虑使用排序键为值的排序对列表。这将让您在这种情况下执行上面概述的窗口优化。如果窗口化在两个维度上进行,您很可能只需要执行一种或另一种优化,但也有二维范围查询结构可以为您提供这一点。

假设我关于固定数据大小的假设是错误的;相反,您将数据添加到列表的末尾,但现有数据点不会更改。在这种情况下,您可能最好使用链接的类似队列的结构,该结构会删除旧数据点而不是数组,因为增长数组往往会在应用程序中引入不必要的卡顿。

在这种情况下,您的优化是预先绘制到队列后面的缓冲区中——当新元素进入队列时,将整个缓冲区向左移动并仅绘制包含新元素的区域。

如果问题在于数据输入的/速率/,那么使用排队结构并跳过元素——或者在将它们添加到队列时折叠它们,存储/绘制每个n元素,或者类似的东西。

如果渲染过程占用了您所有的时间,请考虑在后台线程上渲染并存储渲染的图像。这将让您可以花尽可能多的时间进行重绘——图表本身的帧速率会下降,但整体应用程序响应速度不会下降。