unlockCanvasAndPost中的IllegalArgumentException(android动态壁纸)

时间:2012-10-06 09:54:10

标签: java android multithreading live-wallpaper

我创建了我的第一个动态壁纸,在一个单独的线程中实现绘图。所以现在我有了一个WallpaperService和我的WallpaperPainter来完成这项工作。问题是我在某些设备上获得了IllegalArgumentException unlockCanvasAndPost方法(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 个答案:

答案 0 :(得分:2)

如果错误是: UnlockAndPost失败,则表示解锁没有缓冲区。 在this.surfaceHolder.unlockCanvasAndPost(c);之后 你可以追加
this.surfaceHolder.lockCanvas();
(对不起,我的英语水平很差)

答案 1 :(得分:2)

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

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

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

你需要做的就是修复bug - 就是在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;
}

答案 2 :(得分:1)

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

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

    while (run) {
        Canvas c = null;
        ...
    
  • 您的run字段应标记为volatile,因为多个帖子都可以访问该字段。

  • 切勿在{{1​​}}块内调用Thread.sleep(...)。这是一个非常糟糕的做法,因为它不必要地阻止其他线程。

  • 确保至少记录您的例外情况。对synchronized要格外小心。所有这一切都掩盖了你的问题。

  • catch (Exception e) {}循环中执行join()没有多大意义。如果您的线程被中断,您应该中断绘制线程并退出。

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

    while

答案 3 :(得分:1)

我的动态壁纸也遇到了同样的问题。在Nexus 5模拟器上运行正常,但是当我在Nexus 10模拟器上运行它时,它会在应用程序加载时崩溃。

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

有关如何使用错误的分辨率修复皮肤的详细信息,请参阅: Android Studio - Tablet emulator not showing correct resolution