我正在尝试使用SurfaceView
制作一个简单的秒表。它显示百分之一秒,因此它会尽可能频繁地更新以保持平滑的动画。它在我运行4.0.3的平板电脑和运行4.0.4的手机上运行得非常好,但是当我在4.4.4上尝试它时,似乎有一些我无法解释的撕裂。
底部图像显示了应该发生的事情,并且大多数情况下都有效。但是,每隔几秒就有一次闪烁。当我设法在正确的时间暂停时,我看到一些的数字被转换到右边。他们只向右移动(顶部图像)。这种情况只发生在几分之一秒内,只要足够长就会引起明显的闪烁。
请注意,数字位于画布上,使用计算一次的值(在onMeasure()
中)并存储在类字段中。它们在初始化后不会改变。我通过记录每个onDraw()
内的像素值来测试它。
在上图中,它是转置的分钟值,但有时它是其他数字。它们似乎总是被转换成一组;分钟,秒或两个厘秒。
此外:这只影响drawText()
。我有更多复杂版本的秒表,有很多路径,圆圈等。问题只发生在文字上。
我查看了有关SO和其他地方的几个问题和评论。这就是我所确定的:
我认为这不是缓冲问题。这种行为似乎与此类似 基于缓冲区的撕裂的描述,但在这种情况下我不会想到 问题可能是旧数据被发布到屏幕上,因为 数字从不在显示的位置绘制。
我在评论中读到它可能与该功能有关
更新onDraw()
之间多次调用的值
方法调用。我试过限制更新,但问题
仍然存在。
我还尝试绘制到临时位图并使用canvas.drawBitmap()
onDraw()
功能再次无济于事。
基本上,我想知道:
答案 0 :(得分:1)
在阅读@ fadden的评论后,我能够更有效地搜索。
似乎我的错误是试图在动画线程中调用onDraw()
。当我将这一个电话改为postInvalidate()
时,它立即解决了问题。简而言之,动画循环的内部如下所示:
holder = view.getHolder();
canvas = holder.lockCanvas();
if (canvas != null) {
synchronized (holder) {
if (view != null) {
view.DEBUG_THREADCALLS++;
// NOT view.onDraw(), but:
view.postInvalidate();
}
}
}
根据我的理解,对onDraw()
的调用会导致问题,因为它会导致应用程序同时绘制View
和Surface
。
我猜这个问题只出现在更现代的Android版本中的原因可能是因为较新的设备具有更高的刷新率,因此问题更加明显。我注意到该解决方案还显着提高了我最老的设备的帧速率,这可能是因为它不能同时如此努力地吸引到两个地方。
<强>更新强>
根据以下极其有用的评论的进一步建议,我完全删除了SurfaceView,现在使用单独的动画线程绘制自定义视图。即使在较旧的设备上,结果也是令人难以置信的流畅动画,远远优于SurfaceView!所以对于其他试图用SurfaceView进行动画制作的人,我说:除非你有充分的理由,否则不要!