【问题标题】:Why is lockCanvas() slow?为什么 lockCanvas() 慢?
【发布时间】:2011-05-16 07:11:40
【问题描述】:

我正在实现一个 SurfaceView 子类,我在其中运行一个单独的线程来绘制到 SurfaceHolders 画布上。 我正在测量打电话给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);
            }
}

【问题讨论】:

  • 你找到解决办法了吗?

标签: android surfaceview android-canvas


【解决方案1】:

每次更改表面时,您都会创建一个线程。您应该在surfaceCreated 中启动您的线程并在surfaceDestroyed 中终止它。 surfaceChanged 用于您的表面尺寸发生变化时。

来自 SurfaceView.surfaceCreated 文档:

在第一次创建表面后立即调用它。这个实现应该启动他们想要的任何渲染代码。请注意,只有一个线程可以绘制到 Surface 中,因此如果您的正常渲染将在另一个线程中进行,则不应在此处绘制到 Surface。

多个线程可能会让您受到限制。来自 SurfaceHolder.lockCanvas 文档:

如果在 Surface 未准备好时(在 Callback.surfaceCreated 之前或 Callback.surfaceDestroyed 之后)重复调用此函数,您的调用将被限制到较慢的速度以避免消耗 CPU。

但是,我不相信这是唯一的问题。 surfaceChanged 真的会被多次调用吗?

【讨论】:

  • 当文档说 only one thread can ever draw into a Surface ... 应该从表面上理解这个声明,还是他们说“... 可以同时绘制到 Surface 中 i>”。
  • 我认为应该从表面上看。即使没有,您也必须处理序列化绘图命令。 (这可能是他们要求您在单个线程上提交它们的原因。)根据stackoverflow.com/a/11258546/79125 我是对的(但我们只是互联网上的两个人;)。
  • 哦。我绝对喜欢一个好的教程(该响应链接到)。谢谢。我希望我能给你两个 +1 =)
【解决方案2】:

这与lockCanvas在android图形框架中的实际实现方式有关。

您可能应该已经知道lockCanvas 将返回您将用于绘制的免费块内存。 free,表示这段内存没有用于作曲,也没有用于显示。在内部,简单来说,一个 SurfaceView 是由双缓冲区备份的,一个用于绘图,一个用于合成/显示。这个双缓冲区由 BufferQueque 管理。 如果合成/显示比绘图慢,我们必须等到有空闲缓冲区可用。

【讨论】:

    【解决方案3】:

    【讨论】:

    • 好的,谢谢。我之前已经阅读过,并且理解了这些概念。但我还没有找到解决办法。即使我删除了 synchronized 块(不推荐),它也无济于事。仍然是那些重要的时机。
    猜你喜欢
    • 2021-09-03
    • 2013-10-30
    • 2014-06-15
    • 2011-03-23
    • 1970-01-01
    • 2016-09-28
    • 2020-02-08
    • 2012-07-17
    • 2011-11-07
    相关资源
    最近更新 更多