5

我创建了我的第一个动态壁纸,在单独的线程中实现绘图。所以现在我有一个 WallpaperService 和我的 WallpaperPainter 来完成这项工作。问题是我在某些设备上获得了IllegalArgumentExceptioninunlockCanvasAndPost方法(Samsung Note 就是其中之一)。我已经阅读了所有我能找到但无法修复该错误的建议。似乎unlockCanvasAndPost在表面被破坏时调用了,因此画布无效。这是代码的基本部分:

在墙纸服务中:

    @Override
    public void onSurfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        super.onSurfaceChanged(holder, format, width, height);
        painting.setSurfaceSize(width, height);
    }

    @Override
    public void onSurfaceCreated(SurfaceHolder holder) {
        super.onSurfaceCreated(holder);
        painting.start();
    }

    @Override
    public void onSurfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        painting.stopPainting();
        while (retry) {
            try {
                painting.join();
                retry = false;
            } catch (InterruptedException e) { }
        }
        super.onSurfaceDestroyed(holder);
    }

在绘画线程中:

public void stopPainting() {
    this.run = false;
    synchronized(this) {
        this.notify();
    }
}

public void run() {
    this.run = true;
    Canvas c = null;
    while (run) {
        try {
            synchronized (this) {
                Thread.sleep(50);
                c = this.surfaceHolder.lockCanvas();
                doDraw(c);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (c != null) {
                this.surfaceHolder.unlockCanvasAndPost(c); // << -- HERE IS THE PROBLEM
            }
        }
        // if pause...
        synchronized (this) {
            if (wait) {
                try {
                    wait();
                } catch (Exception e) { }
            }
        }
    }
}

谁能给我任何线索我做错了什么?我是 Java 和 Android 的新手。

4

4 回答 4

2

如果错误是:UnlockAndPost Failed,这意味着它没有解锁缓冲区。之后this.surfaceHolder.unlockCanvasAndPost(c);
可以追加
this.surfaceHolder.lockCanvas();
(对不起我的英语水平不好)

于 2013-03-08T06:25:44.877 回答
2

当您打开壁纸预览时,创建对象 WallpaperService 并进一步创建 Engine 实例。然后流开始绘制壁纸。

然后,当您单击“设置壁纸”时 - 不会创建 WallpaperService 的新实例。但他调用了 onCreateEngine() 方法,该方法返回另一个(第二个)Engine 实例。它也运行自己的线程。

现在你有两个竞争线程!!!因此它们会导致抛出异常。

修复该错误所需要做的就是编写正确的方法 onCreateEngine()。

替换这个:

@Override
public Engine onCreateEngine() {
    return new SampleEngine();
}

对此:

private SampleEngine engine;

@Override
public Engine onCreateEngine() {

    if (engine!=null) {
        engine.painting.stopPainting();
        engine = null;
    }
    engine = new SampleEngine();
    return engine;
}
于 2013-04-26T13:43:34.870 回答
1

我没有看到明确的问题,但这里有一些想法。

  • 您有可能解锁尚未锁定的画布。我将设置c = null;在循环的顶部,否则下一次循环时将解锁while先前的值。c

    while (run) {
        Canvas c = null;
        ...
    
  • 您的run字段应标记为,volatile因为它由多个线程访问。

  • Thread.sleep(...)永远不要在synchronized块内调用。这是一个非常糟糕的做法,因为它不必要地阻塞了其他线程。

  • 确保您至少记录您的异常。要格外小心catch (Exception e) {}。所做的只是掩盖你的问题。

  • join()做内部while循环没有多大意义。如果您的线程被中断,您应该中断绘画线程并退出。

  • 由于您既在睡觉在等待,因此删除睡眠并执行以下操作会更有意义:

    try {
       synchronized (this) {
           if (wait) {
              wait();
           else {
              wait(50);
           }
       }
    } catch (Exception e) {
       e.printStackTrace();
    }
    
于 2012-10-10T13:15:59.163 回答
1

我的动态壁纸也有同样的问题。在 Nexus 5 模拟器上它运行良好,但是当我在 Nexus 10 模拟器上运行它时,它会在应用程序加载的那一刻崩溃。

我发现问题是因为模拟器的默认皮肤有错误的分辨率。在我将皮肤更改为“无皮肤”之后,我就不再遇到崩溃了。

有关如何修复分辨率错误的皮肤的更多信息,请参阅: Android Studio - 平板电脑模拟器未显示正确分辨率

于 2015-09-21T14:39:01.433 回答