在动态壁纸的开发过程中,我遇到了两个问题,并希望找到最佳的解决方法。
WallpaperService.Engine.onSurfaceCreated()
WallpaperService.Engine.onSurfaceChanged()
和WallpaperService.Engine.onDestroyed()
在某些情况下,Android会在WallpaperService.Engine.onSurfaceCreated()
被调用后调用WallpaperService.Engine.onSurfaceChanged()
和WallpaperService.Engine.onDestroyed()
。它违反了文档定义的WallpaperService.Engine
执行协议。
我当前的解决方案只是拥有显式标记(mAlreadyDestroyed
),默认情况下 false ,但在onDestroy()
回调中设置为 true 。 WallpaperService.Engine.onSurfaceCreated()
和WallpaperService.Engine.onSurfaceChanged()
检查此标记,如果 true 则不执行任何操作。有没有人面对这个问题以及你如何解决它?
以下是您可以用来检查此问题的简单代码:
public class LWService extends WallpaperService {
/**
* Will show the bug with calling {@link #onSurfaceCreated(SurfaceHolder)}
* and other surface callbacks after {@link #onDestroy()}.
*
*/
private class LWEngineTest1 extends Engine {
/**
* Will be set to <code>true</code> in {@link #onDestroy()}.
*/
private boolean mAlreadyDestroyed = false;
/**
* Log debug level message with adding object instance info to better
* LogCat readability.
*
* @param message
* message to log
*/
private void logD(final String message) {
Log.d("LW_BUG_TEST", this.toString() + ":" + message);
}
/**
* Log error level message with adding object instance info to better
* LogCat readability.
*
* @param message
* message to log
*/
private void logE(final String message) {
Log.e("LW_BUG_TEST", this.toString() + ":" + message);
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
logD("onCreate()");
}
@Override
public void onDestroy() {
logD("onDestroy()");
mAlreadyDestroyed = true;
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
logD("onSurfaceCreated()");
if (mAlreadyDestroyed) {
logE("onSurfaceCreated() after onDestroy()");
}
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
logD("onSurfaceChanged()");
if (mAlreadyDestroyed) {
logE("onSurfaceChanged() after onDestroy()");
}
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
logD("onSurfaceDestroyed()");
if (mAlreadyDestroyed) {
logE("onSurfaceDestroyed() after onDestroy()");
}
try {
// To reveal the bug, without this line you may not got the
// issue. Of course it is absolutely synthetic but allow to get
// the issue guaranteed
Thread.sleep(4000);
} catch (InterruptedException exc) {
}
}
}
@Override
public Engine onCreateEngine() {
return new LWEngineTest1();
}
}
以下是登录Samsung Galaxy S(Android 2.2.1)时的内容。只需将此示例壁纸设置为当前,然后选择另一个(仅保留相关的日志条目):
08-14 14:53:55.964: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@48008a28:onCreate()
08-14 14:53:55.980: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@48008a28:onSurfaceCreated()
08-14 14:53:55.980: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@48008a28:onSurfaceChanged()
08-14 14:54:17.651: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@4800f0b0:onCreate()
08-14 14:54:17.667: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@4800f0b0:onSurfaceCreated()
08-14 14:54:17.667: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@4800f0b0:onSurfaceChanged()
08-14 14:54:18.261: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@48008a28:onSurfaceDestroyed()
08-14 14:54:22.265: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@48008a28:onDestroy()
08-14 14:54:26.675: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@4800f0b0:onSurfaceDestroyed()
08-14 14:54:30.675: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@4800f0b0:onDestroy()
08-14 14:54:30.687: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@4800f0b0:onSurfaceCreated()
08-14 14:54:30.687: ERROR/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@4800f0b0:onSurfaceCreated() after onDestroy()
08-14 14:54:30.687: DEBUG/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@4800f0b0:onSurfaceChanged()
08-14 14:54:30.687: ERROR/LW_BUG_TEST(19274): lwtests.LWService$LWEngineTest1@4800f0b0:onSurfaceChanged() after onDestroy()
WallpaperService.Engine.onSurfaceDestroyed()
在表面被实际销毁后调用在某些情况下,Android可能会在表面被实际销毁后调用WallpaperService.Engine.onSurfaceDestroyed()
。这违反了SurfaceHolder.Callback.onSurfaceDestroyed()
规范。此问题非常具体,即使在您的代码中出现也可能不被注意。如果您有单独的渲染线程,您将注意到该问题的最多时间。即使在主应用程序的线程收到提到的WallpaperService.Engine.onSurfaceDestroyed()
之前,呈现线程也可能会注意到死表面。在我的OpenGL渲染中,我在执行eglSwapBuffers()
时得到了 EGL_BAD_NATIVE_WINDOW 。
我目前的解决方案是忽略指定的EGL错误,但我真的不喜欢这种解决方案。我的代码充满了自检断言和错误条件检查,我不想删除这些断言和检查(并且忽略特定的错误代码就是这种事情)。这个问题是否存在任何解决方案?
以下是您可以用来检查此问题的简单代码:
public class LWService extends WallpaperService {
/**
* Will show the bug with non-conform to documentation (specification)
* {@link #onSurfaceDestroyed(SurfaceHolder)}.
*/
private class LWEngineTest2 extends Engine {
/**
* Log error level message with adding object instance info to better
* LogCat readability.
*
* @param message
* message to log
*/
private void logE(final String message) {
Log.e("LW_BUG_TEST", this.toString() + ":" + message);
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
if (holder.getSurface().isValid() && null == holder.lockCanvas()) {
logE("onSurfaceDestroyed() : uuups ... broken surface");
}
// If you have separate rendering thread it may already notice that
// surface already invalid and encounter problems due to that fact.
// E.g. eglSwapBuffers() may generate EGL_INVALID_NATIVE_WINDOW
// error.
// mRenderingThread.releaseSurface();
}
}
@Override
public Engine onCreateEngine() {
return new LWEngineTest1();
}
}
以下是我登录Acer A500(Android 3.1)的内容。只需选择此壁纸进行预览,然后在预览活动中按“返回”按钮(仅保留相关的日志条目):
08-14 16:10:55.580: ERROR/Surface(31787): Surface (identity=1298) state = -19
08-14 16:10:55.660: ERROR/Surface(31787): getBufferLocked(0, 0, 0, 0, 00000033) failed (No such device)
08-14 16:10:55.660: ERROR/Surface(31787): dequeueBuffer failed (No such device)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): Exception locking surface
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): java.lang.IllegalArgumentException
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at android.view.Surface.lockCanvasNative(Native Method)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at android.view.Surface.lockCanvas(Surface.java:346)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at com.android.internal.view.BaseSurfaceHolder.internalLockCanvas(BaseSurfaceHolder.java:184)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at com.android.internal.view.BaseSurfaceHolder.lockCanvas(BaseSurfaceHolder.java:157)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at lwtests.LWService$LWEngineTest2.onSurfaceDestroyed(LWService.java:271)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at android.service.wallpaper.WallpaperService$Engine.reportSurfaceDestroyed(WallpaperService.java:773)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at android.service.wallpaper.WallpaperService$Engine.detach(WallpaperService.java:790)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at android.service.wallpaper.WallpaperService$IWallpaperEngineWrapper.executeMessage(WallpaperService.java:902)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:61)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at android.os.Handler.dispatchMessage(Handler.java:99)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at android.os.Looper.loop(Looper.java:132)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at android.app.ActivityThread.main(ActivityThread.java:4025)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at java.lang.reflect.Method.invokeNative(Native Method)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at java.lang.reflect.Method.invoke(Method.java:491)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
08-14 16:10:55.660: ERROR/BaseSurfaceHolder(31787): at dalvik.system.NativeStart.main(Native Method)
08-14 16:10:55.660: ERROR/LW_BUG_TEST(31787): lwtests.LWService$LWEngineTest2@407ba3b8:onSurfaceDestroyed() : uuups ... broken surface
我已在Android问题跟踪器(19243,19245)中报告了这两个问题,但实际上知道如何为已发布的Androids版本解决这些问题更为有趣。这就是为什么我在这里要求任何人都知道的解决方案。虽然我已经有了自己的解决方法(可能会对某些人有用),但我也想知道另一种解决这些问题的可能性。
提前致谢。
答案 0 :(得分:1)
可以并行执行多个引擎。你必须管理它们。要检查这一点,只需为您创建的每个引擎添加一个ID。您可以通过以下方式验证:
HotelCategory
我注意到在不同设备上的行为略有不同。所以我建议你在不同的设备上测试你的解决方案。
答案 1 :(得分:0)
我在Incredible运行的Cyanogen 7.0.3(Gingerbread 2.3.3)上试用了你的代码。我没有看到你遇到的问题。
以下是经过Picker&gt;后的日志结果。预览&gt;设置壁纸:
08-24 07:47:04.261: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@40630938:onCreate()
08-24 07:47:04.301: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@40630938:onSurfaceCreated()
08-24 07:47:04.301: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@40630938:onSurfaceChanged()
08-24 07:47:10.187: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@4062d100:onCreate()
08-24 07:47:10.227: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@4062d100:onSurfaceCreated()
08-24 07:47:10.227: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@4062d100:onSurfaceChanged()
08-24 07:47:10.858: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@40630938:onSurfaceDestroyed()
08-24 07:47:14.862: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@40630938:onDestroy()
然后在设置完全不相关的壁纸后,该实例将被销毁:
08-24 07:48:33.268: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@4062d100:onSurfaceDestroyed()
08-24 07:48:37.272: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@4062d100:onDestroy()
这是Picker&gt;之后的结果吗?预览&gt;返回(没有设置壁纸):
08-24 07:49:50.133: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@4063eb20:onCreate()
08-24 07:49:50.173: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@4063eb20:onSurfaceCreated()
08-24 07:49:50.173: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@4063eb20:onSurfaceChanged()
08-24 07:49:54.157: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@4063eb20:onSurfaceDestroyed()
08-24 07:49:58.161: DEBUG/LW_BUG_TEST(32534): LWService$LWEngineTest1@4063eb20:onDestroy()