如何在SurfaceView中冻结动画的最后一帧?

时间:2013-08-28 12:31:58

标签: java android performance android-canvas android-animation

我使用具有以下calssic run()方法的线程在SurfaceView上绘图:

@Override
public void run() {
    while (mRun) {
        Canvas canvas = null;
        synchronized (mSurfaceHolder) {
                try {
                    canvas = mSurfaceHolder.lockCanvas();
                    update();
                    doDraw(canvas);
                } finally {
                    if (canvas != null) {
                        mSurfaceHolder.unlockCanvasAndPost(canvas);
                    }
                }
        }
    }
}

如果从那一刻起即将绘制的下一帧与前一帧完全相同,我想保存一些工作,所以我跳过了onDraw,但是我得到了flickering issues due to the double buffering mechanism。 然后我继续做了这样的事情:

@Override
public void run() {
    while (mRun) {
        Canvas canvas = null;
        synchronized (mSurfaceHolder) {
            if (mIsAnimating) {          // <---- Look ma! A flag!!!
                try {
                    canvas = mSurfaceHolder.lockCanvas();
                    update();
                    doDraw(canvas);
                } finally {
                    if (canvas != null) {
                        mSurfaceHolder.unlockCanvasAndPost(canvas);
                    }
                }
            }
        }
    }
}

如果我关闭mIsAnimating标志,从而阻止我的运行循环锁定画布并在其上绘图,一切都像魅力 - 我做了一些动画,在完成后,我可以冻结绘图周期并保持动画在屏幕上的最后一帧。

但是我必须从Android docs看到以下内容:

  

在unlockCanvas()之间永远不会保留Surface的内容   和lockCanvas(),因此,Surface区域内的每个像素   必须写。这个规则的唯一例外是脏的时候   指定了矩形,在这种情况下,将使用非脏像素   保留。

那么......我的代码怎么运作?

3 个答案:

答案 0 :(得分:1)

我认为发生了两件事之一,首先(非常不可能)你可能会不小心重复绘制动画的最后一帧,如果不是,那么这意味着你的SurfaceView没有因视图的任何变化而失效因此保持缓存最后一个像素缓冲区显示,为了测试它,在屏幕上设置一个按钮,当SurfaceView被“冻结”点击按钮并使按钮本身消失,所以你将强制重绘所有元素在屏幕上,如果动画消失意味着它实际上被缓存...

问候!

答案 1 :(得分:1)

你的问题很好。 SurfaceView是一种奇怪的动物。

首先,View s,一般来说,默认情况下不使用缓存绘图(据我所知,这仍然是正确的),SurfaceView没有做任何事情来启用它。所以我有理由相信没有缓存。

SurfaceView 正在做什么是在视图层次结构的Window中挖洞,以便您可以看到另一个Window或直接在框架上绘制的内容缓冲在它后面。 Android在其PorterDuff.Mode枚举中添加了一个不存在的Porter-Duff模式来完成这种奇怪的行为。因此,正常的绘图规则不适用于SurfaceView。无效或请求布局只会再次削减漏洞。视图层次结构不知道或关心在屏幕的该区域中实际绘制的内容,因此除非您以其他方式专门绘制它(例如,使用SurfaceHolder获取Canvas在一个单独的Window)上的那个区域,有一个合理的机会它只是在那里没有被触及。

所以我真正想到的是,Android根本不是重绘帧缓冲区的那一部分。从Surface那里得到的内容停留在那里,而其余的视图层次结构围绕它绘制。 Surface非常好的资源可以解除分配,你永远不会知道。

我很好奇如果你切换到另一个Activity或主屏幕然后回来会发生什么?我的猜测是你的最后一帧将不再存在。如果是,那么SurfaceView甚至比我知道的更奇怪......

编辑:只是一个简短的说明...... Window基本上是Surface,具有一些额外的功能。我习惯使用Window这个词与Surface互换是因为Surface基本上是ANativeWindow在本机方面。

答案 2 :(得分:0)

仅在应用程序表面更改时重绘。这很好用。但是 - 这就是Android文档所指的内容 - 任何其他应用程序,服务,Toast或其他任何东西都可以覆盖你的表面部分一段时间。以Toast中的Service为例。当Toast消失时,您的应用和SurfaceView必须更新屏幕的该部分。但是在代码中,只要没有设置标志,就不会更新。