3

我正在使用具有以下 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,但由于双缓冲机制,我遇到了闪烁问题。然后我继续做这样的事情:

@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 文档中的以下内容:

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

那么......我的代码是怎么工作的?

4

3 回答 3

2

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

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

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

所以我真正认为正在发生的是Android根本没有重绘帧缓冲区的那部分。从那里绘制的Surface内容保留在那里,而视图层次结构的其余部分则围绕它绘制。井的资源Surface可能会被释放,你永远不会知道。

我很好奇如果您切换到其他Activity屏幕或主屏幕并返回会发生什么?我的猜测是你的最后一帧将不再存在。如果是的话,那SurfaceView比我所知道的还要奇怪……

编辑:只是一个简短的说明...... aWindow基本上是Surface带有一点额外功能的。我习惯Window交替使用这个术语Surface是因为 aSurface基本上ANativeWindow是事物的本机方面。

于 2013-09-08T14:19:28.007 回答
1

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

问候!

于 2013-09-06T16:34:05.713 回答
0

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

于 2013-09-08T16:31:42.420 回答