为什么lockCanvas()方法很慢?

8

我正在实现一个SurfaceView子类,在其中运行一个单独的线程来绘制到SurfaceHolders Canvas上。 我在调用lockCanvas()之前和之后测量时间,结果从约70毫秒到100毫秒不等。 有人能指出为什么会出现如此高的计时吗? 以下是相关代码:

public class TestView extends SurfaceView implements SurfaceHolder.Callback {

....

boolean created;
public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {

   mThread = new DrawingThread(mHolder, true);
   mThread.onWindowResize(width, height);
   mThread.start();
}

public void surfaceCreated(SurfaceHolder holder) {

    created = true;
}

public void surfaceDestroyed(SurfaceHolder holder) {
    created = false;

}
class DrawingThread extends Thread {
public void run() {
while(created) {



            Canvas canvas = null;
            try {
                            long t0 = System.currentTimeMillis();
            canvas = holder.lockCanvas(null);
            long t1 = System.currentTimeMillis();
                            Log.i(TAG, "Timing: " + ( t1 - t0) );
            } finally {
                holder.unlockCanvasAndPost(canvas);
            }
}

你找到解决方案了吗? - Ivan Vovk
3个回答

5
每次更改Surface时都会创建一个线程。你应该在surfaceCreated中启动线程,并在surfaceDestroyed中销毁它。 surfaceChanged是用于更改表面尺寸的。
来自SurfaceView.surfaceCreated文档:
这将在表面首次创建后立即调用。其实现可启动任何渲染代码。请注意,仅有一个线程可以绘制到表面,因此如果正常渲染将在另一个线程中进行,则不应在此处绘制到表面。
多个线程可能会导致限制。从SurfaceHolder.lockCanvas文档中可知:
如果在Surface未准备好时(在Callback.surfaceCreated之前或在Callback.surfaceDestroyed之后)反复调用此方法,则您的调用速度将被限制以避免消耗CPU资源。
然而,我并不确定这是唯一的问题。 surfaceChanged 是否确实被调用了多次?

当文档中说“只有一个线程可以绘制到Surface”时,这个声明应该被直接理解吗?还是他们的意思是“...在同一时间内只能有一个线程绘制到Surface”。 - Brian Vandenberg
1
我认为应该直接采纳。即使不是这样,你也必须处理序列化绘制命令。(这可能就是为什么他们要求你在单个线程上提交它们的原因。) 根据https://dev59.com/HWXWa4cB1Zd3GeqPN4yX#11258546,我是正确的(但我们只是网上的两个人;)。 - idbrii
哦,我绝对喜欢好的教程(该回复链接到了一个)。谢谢。我希望我能为你点两个+1 =) - Brian Vandenberg

2

这与Android图形框架中lockCanvas的实际实现有关。

你可能已经知道lockCanvas将会返回一个空闲的内存块,你可以用来进行绘制。在这里,空闲意味着这个内存块还没有被用于合成和显示。简单地说,一个SurfaceView由双缓冲区支持,其中一个用于绘制,一个用于合成/显示。这个双缓冲区是由BufferQueue进行管理。如果合成/显示比绘制慢,我们必须等待直到有可用的空闲缓冲区。


1

好的,谢谢。我之前已经看过那个了,也理解了其中的概念。但是我还没有找到解决方案。即使我移除了 synchronized 块(虽然这并不被推荐),它对我也没什么帮助。时间仍然很长。 - kaneda

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