我创建了我的第一个动态壁纸,在一个单独的线程中实现绘图。所以现在我有了一个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的新手。
答案 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