我想绘制一个实时更新的图表(从右边开始)。我能想到的最有效的方法是将 x[0 .. width-2] 中的所有内容复制 1 个像素,然后在 x[width-1] 处绘制新值。
我对 Android 几乎没有经验,但据我所知,Canvas 根本无法对其内容进行操作。我每次都需要重新绘制整个屏幕吗?这涉及缩放和平滑,所以我担心它会很慢。
我应该画一个 byte[][] 然后用它来画到屏幕上(每次都把我的缓冲区的内容向左移动)?
Regarding performance, without profiling we cannot say.
It may be that line drawing is hardware accelerated on your target phone, and you should draw the graph from scratch using line-drawing primitives each frame.
On the other hand, the straightforward pixel manipulation of an image buffer would be:
Create an image that is the right size and clear it to a "background_color
". This image needs to have setpixel() functionality.
Have an array of values that record the y of each x time, so for any column you know where you last plotted your graph.
Treat this "chart_image
" and "chart_array
" as a circular buffer. For each time step:
Y = ...;
X = time_since_start % chart_width;
chart_image.setpixel(X,chart_array[X],background_color); // clear previous line
chart_array[X] = Y;
chart_image.setpixel(X,chart_array[X],foreground_color); // draw new plot
And now you need to blit it. You need to blit the image twice:
X = time_since_start % chart_width;
// the newest data is on the left of the chart_image but gets drawn on the right side of the output
blit(out_x+X,out_y, // destination coordinates
chart_image,
0,0, // top left of part of chart_image to blit
X,chart_height); // bottom right of chart_image part
// the oldest data is on the right of the chart_image but gets drawn on the left side of the output
blit(out_x,out_y,
chart_image,
X,0,
chart_width,chart_height);
Things get more tricky if you want to use lines rather than individual pixels, but a drawline()
instead of a setpixel()
can make that work with this approach too.
(Apologies for not knowing the Android APIs; but the approach is generic.)
如果您的图表是有界的,请尝试将其全部渲染一次到一个图像,然后将该图像的相关部分blit到您的画布上。尽量避免实际“移动”缓冲区中的像素,因为这可能会在您的读取和写入之间引入依赖关系,并且可能会真正降低性能。实际上,从一个缓冲区复制到另一个缓冲区并交替将哪个缓冲区传送到屏幕上可能会更好。最后,如果您最终不得不手动处理像素,请确保您以行而不是列在图像上运行,并且从行的开头开始以帮助缓存。
只是一个想法,您可能已经考虑过,但我不会改变缓冲区的内容 - 我只是尝试像循环缓冲区一样使用它。保留当前列的索引,一旦您再次绕到最左侧的列,您可以分两段绘制到目标 - 当前列右侧的内容和左侧的内容,包括最近填充的列。这样您就不必四处移动任何东西,并且每次屏幕刷新只是两个段的两个 blit(位图副本)。如果那一点太慢了,您仍然可以始终将它们绘制到第二个屏幕外缓冲区中,然后一次将整个内容传输到屏幕上。当然,屏幕上的一个大块相当快,不是吗?
由于我可以理所当然地将图形数据存储在内存中,因此重绘它应该不是问题。每帧重绘一组点一点也不费力。移动内存将是密集的,它移动所有东西而不是只绘制你需要的东西。最坏的情况,因为它是时间的函数,显示器的每列只有一个值,系统必须绘制的横向大约 800 像素/值。这是微不足道的。你有没有介绍过这个?编辑:记住,不是系统必须绘制每个点,它只绘制内存,然后使用它的原语。不要认为它重复绘制点,转储到视频内存,然后再一次。