调用Drawable.draw()时防止"闪烁"

Oli*_*rth 3 android surfaceview android-emulator

我有一个小实验应用程序(基本上是Android SDK中LunarLander演示的非常简化的版本),只有一个.我有一个"精灵",我定期抽入的在不同位置的对象,而不试图抹去以前的图像.从而:SurfaceViewDrawableSurfaceViewCanvas

private class MyThread extends Thread {
    SurfaceHolder holder;  // Initialised in ctor (acquired via getHolder())
    Drawable      sprite;  // Initialised in ctor
    Rect          bounds;  // Initialised in ctor

    ...

    @Override
    public void run() {
        while (true) {
            Canvas c = holder.lockCanvas();
            synchronized (bounds) {
                sprite.setBounds(bounds);
            }
            sprite.draw(c);
            holder.unlockCanvasAndPost(c);
        }
    }

    /**
     * Periodically called from activity thread
     */
    public void updatePos(int dx, int dy) {
        synchronized (bounds) {
            bounds.offset(dx, dy);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在模拟器中运行,我看到的是,在发生一些更新之后,图像的几个旧"副本"开始闪烁,即出现和消失.我最初假设也许我误解了a的语义Canvas,并且它以某种方式保持了"层次",并且我正在将它捶打死亡.然而,我后来发现,如果我尝试以大约每200毫秒的速度更新,我只会得到这种效果.所以我的下一个最好的理论是,这可能是模拟器无法跟上并撕裂显示器的神器.(我还没有要测试的物理设备.)

这些理论中哪一个是正确的吗?

注意:我实际上并不想在实践中这样做(即绘制数百个同一事物的重叠副本).但是,我想了解为什么会这样.

环境:

  • Windows 7上的Eclipse 3.6.1(Helios)
  • JDK 6
  • Android SDK工具r9
  • 应用程序的目标是Android 2.3.1

切向问题:

我的run()方法本质上是LunarLander示例如何工作的精简版本(删除了所有多余的逻辑).我不太明白为什么这不会让CPU饱和,因为似乎没有什么可以阻止它以完全的毛皮运行.任何人都可以澄清这个吗?

Reu*_*ton 12

好吧,我以与你类似的方式屠杀了Lunar Lander,看到闪烁的我可以告诉你,你所看到的是每个人Surface都有的双缓冲机制的简单人工制品.

当您在Canvas附加到a 上绘制任何内容时Surface,您将绘制到"后退"缓冲区(不可见的缓冲区).当你unlockCanvasAndPost()将缓冲区交换过来时......你突然变得可见,因为"后退"缓冲区变成"前面",反之亦然.所以你的下一帧绘图是在旧的"前"缓冲区完成的......

关键是你总是在备用帧上绘制单独的缓冲区.我想在图形架构中有一个隐含的假设,你总是要写每个像素.

理解了这一点后,我认为真正的问题是它为什么不闪烁硬件?在经历了多年的图形驱动程序研究之后,我可以猜测原因,但却犹豫不决.希望上述内容足以满足您对此渲染工艺的好奇心.:-)