在CustomView中连续绘制时性能差

14

用例:

我需要在视图上绘制数百条线和一些文本。我需要实现滚动效果,为此捕获 ACTION_MOVE 事件并重新绘制所有带有更新点的线条。为了达到预期的结果,我尝试了不同的方法,但都没有奏效。

方法1:

我创建了一个自定义类,它扩展了 View。 所有的绘制和计算都直接在我的 onDraw() 方法中完成。由于 onDraw() 方法中有很多的操作,因此应用程序的性能非常差。我甚至使用 Profile GPU rendering 检查了性能,可以看到线条非常高。

方法2:

我创建了一个位图,并在另一个线程中将所有的线条绘制到我的位图上,在 onDraw() 方法中使用 postInvalidate() 绘制位图:

mBufferedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);   
mBufferedBitmap.eraseColor(Color.TRANSPARENT);    
Canvas mBufferedCanvas = new Canvas(mBufferedBitmap);               
drawLines(mBufferedCanvas)    
postInvalidate();

由于我在位图上擦除了所有之前的绘图并使用更新后的点绘制新的线条,因此屏幕会出现闪烁。

方法3

我尝试将自定义类扩展到SurfaceView并在另一个线程中执行所有画布对象的操作。但是由于SurfaceView使用CPU进行绘图操作,在低配置的手机中性能将不佳。

有人可以指导我如何实现更好的性能来完成这个任务吗?


尝试研究一下RenderScript。我自己没有使用过这个框架,但这似乎是一个很好的使用案例。 - Bryan
对于我的使用情况,不需要使用RenderScript。 - VijayRaj
4
不要在onDraw()中分配新的位图,这就是你的fps下降的原因。 - Nikola Despotoski
如果只有线条,您可以使用视图本身来实现,而无需使用位图操作。请勿使用位图操作。 - Chetan Joshi
2个回答

8

使用方法 1可以实现良好的性能。

一个接近您使用场景(绘制线条、少量文本并在手势移动时进行更新)的示例是MPAndroidChart。这是一个开源库,可以获得高性能(如果您想要统计数据,可以查看以下比较结果

需要检查的类是Renderer类,因为这些类包含在图表子类型的onDraw(Canvas c)中绘制代码。你可以看到一些用于实现高性能的技巧:

  1. 不要在渲染循环中进行分配。相反,外部分配并重用/回收变量。查看LineChartRenderer line 199
  2. 使用缓冲区。例如,在MPAndroidChart中,柱状图中四个角的点被缓存,并且缓冲数组被重用。请参见BarBuffer类。
  3. 使用本机的Canvas绘制函数(drawPathdrawLine等)

有关优化渲染的完整提示列表,请参见Android性能缓慢渲染指南


2
方法2是最好的选择。如果您看到闪烁,这意味着在擦除位图并绘制所有线条之前,该位图已经被绘制到屏幕上。如果是这种情况,请使用另一个位图进行双缓冲:

ScreenBitmap是绘制到屏幕上的内容, OffScreenBitmap用于在后台绘制。

将所有线条和文本绘制到OffScreenBitmap中,并在完成后将其复制到ScreenBitmap中。 在onDraw中,绘制ScreenBitmap。

在onSizeChanged中创建这些位图(通常只需创建一次),以便在onDraw中没有分配内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接