使用硬件加速的自定义 Android 视图中的部分无效化

11

我在应用程序中有一个自定义视图,它填充整个活动。

在大多数情况下,当我想要刷新控件时,我会调用没有任何参数的invalidate()

然而,在某些情况下,当我只更改控件的一小部分区域时,我会调用invalidate(Rect)以避免重新绘制整个屏幕。这很重要,因为在这些情况下,我需要尽可能快地更新。

这似乎很好用,但是,当我在Honeycomb中启用硬件加速(即在AndroidManifest.xml中设置android:hardwareAccelerated="true")时,部分重绘似乎不起作用。

如果我在我的onDraw()方法中执行Log.d("FOO", canvas.getClipBounds()),输出只显示整个控件正在更新,而在禁用硬件加速时,我可以得到正确的区域输出。

是否有办法在使用硬件加速时使部分无效化工作?

非常感谢,Matt


我也一直在思考这个问题,而且我遇到了你描述的相同结果。你有尝试使用硬件加速时使部分失效生效的更新吗?或者有关于为什么这不起作用的任何更新吗? - ashughes
1
部分更新有效。显示列表必须包含视图的所有绘图命令,但只有与脏区交叉的命令才会被实际执行。 - Romain Guy
2个回答

15

“Partial redraw”能够正常工作,只会重新绘制屏幕上指定的区域。但是它不会改变画布上的剪切边界。所有的绘制操作都将被记录,但只有与脏区域相交的操作才会被执行。

更新:从Lollipop(API 21)开始,部分失效在View级别上发生(即您无法使某个View的失效范围小于整个View)。


1
抱歉,但我已经做了一个实验。在我的视图的 onDraw(Canvas canvas) 方法中,它会绘制一条长路线,并使用一个小矩形进行无效化。使用硬件加速时,它会绘制整个路径。没有硬件加速时,它只会绘制在矩形内的部分。 - Yeung
1
有了硬件加速,只有脏矩形内的部分才会被绘制。您的测试准确吗?您如何验证结果?顺便说一下,我编写了这个渲染管线 :) - Romain Guy
1
通过硬件加速,在某些情况下,包括恢复活动时,我们强制重新绘制整个窗口。然而,这并不意味着脏区域总是被忽略。您可以在“设置”>“开发人员选项”中打开GPU视图更新来验证此操作。屏幕将在更新窗口的位置闪烁红色。 - Romain Guy
好的,那么为什么在“onDraw”函数中使用/不使用硬件加速时,“getClipBound”的行为会有所不同呢?为什么在仅使用软件模式的情况下返回非全屏矩形? - Roman
2
根据我的经验,在启用硬件加速时,整个视图总是被重新绘制。我通过将视图分成一系列较小的网格视图并仅使更改的视图失效来验证了这一点。在这种情况下,性能得到了很大的提升。 - jjxtra
显示剩余7条评论

1
当启用HA时,渲染管道将使用DisplayList存储绘图命令。即使您在View.invalidate中指定了脏区域,整个显示列表也将被重建(只需想象一下我们如何仅更新一小部分DisplayList,这是不可能的,对吧?)。最终,正如@Romain所说,只有真正的脏区域将被重新绘制。

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