Android的WallpaperService.Engine的问题,需要的解决方法 [英] Android's WallpaperService.Engine issues, workarounds required

查看:4093
本文介绍了Android的WallpaperService.Engine的问题,需要的解决方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在动态壁纸我绝对的发展有两个问题,并想找到最好的可能的解决方法。

During development of Live Wallpapers I jus got two issues and want to find the best possible workarounds.

在某些情况下的Andr​​oid电话的 WallpaperService.Engine.onSurfaceCreated() WallpaperService.Engine.onSurfaceChanged() WallpaperService.Engine.onDestroyed()被调用。它是反对文档定义的 WallpaperService.Engine 执行协议。

Under some circumstances Android call the WallpaperService.Engine.onSurfaceCreated() and WallpaperService.Engine.onSurfaceChanged() after WallpaperService.Engine.onDestroyed() was called. It is against the WallpaperService.Engine execution protocol defined by documentation.

我目前的解决方案是正好有明确的标志( mAlreadyDestroyed )的的默认,但设置的真正的onDestroy()回调。在 WallpaperService.Engine.onSurfaceCreated() WallpaperService.Engine.onSurfaceChanged()检查这个标志,如果什么都不做是的真正的。任何人都面临这样的问题,也和你怎么解决?

My current solution is just to have the explicit flag (mAlreadyDestroyed) which false by default but set to true in onDestroy() callback. The WallpaperService.Engine.onSurfaceCreated() and WallpaperService.Engine.onSurfaceChanged() check this flag and do nothing if it is true. Have anyone face this issue too and how you resolve it ?

下面是一个简单的code你可以用它来检查针对此问题:

Below is a simple code you may use to check for this issue:

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();
    }
}

和下面是我得到的登录三星Galaxy S(的Andr​​oid 2.2.1)。只需设置此示例作为墙纸当前,然后选择另一个(仅相关的日志条目preserved):

And following is what I get in log on Samsung Galaxy S (Android 2.2.1). Just set this sample Wallpaper as current and then select another one (only related log entries preserved):

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()

问题2: WallpaperService.Engine.onSurfaceDestroyed()调用后表面实际上是破坏

在某些情况下Android的可致电 WallpaperService.Engine.onSurfaceDestroyed()后表面实际上破坏。它是对 SurfaceHolder.Callback.onSurfaceDestroyed()规范。这个问题比较非常具体,即使出现在code可以被忽视。大部分时间,你会发现这个问题,如果你有独立的渲染线程。渲染线程可能会注意到,甚至死亡前主应用程序的线程收到提到 WallpaperService.Engine.onSurfaceDestroyed面()。在我的OpenGL渲染的情况下我刚刚得到了 EGL_BAD_NATIVE_WINDOW eglSwapBuffers()执行。

Issue#2: WallpaperService.Engine.onSurfaceDestroyed() called after surface was actually destroyed

Under some circumstances Android may call the WallpaperService.Engine.onSurfaceDestroyed() after surface was actually destroyed. It is against the SurfaceHolder.Callback.onSurfaceDestroyed() specification. This issue is rather very specific and may be unnoticed even if occur in your code. The most time you will notice that issue if you has separate rendering thread. The rendering thread may notice died surface even before your main application's thread receive the mentioned WallpaperService.Engine.onSurfaceDestroyed(). In my case of OpenGL rendering I just got the EGL_BAD_NATIVE_WINDOW when eglSwapBuffers() are executed.

我目前的解决方案就是忽略指定EGL错误,但我真的不喜欢这类解决方案。我的code充满自我检查的断言和错误状况检查和我不喜欢删除这些断言和检查(和特定的错误code无视这样一种东西)。是否有任何解决方案存在这个问题?

My current solution is just to ignore the specified EGL error but I really don't like such kind of solutions. My code full of self-checking assertions and error conditions checks and I don't like to remove these assertions and checks (and specific error code ignoring is such kind of thing). Is there are any solutions exists for this issue ?

下面是一个简单的code你可以用它来检查针对此问题:

Below is a simple code you may use to check for this issue:

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();
    }
}

和下面是我在登录宏碁A500(3.1 Android版)获得。只要选择这种壁纸为preVIEW然后preSS后退按钮,在preVIEW活动(仅限于有关的日志条目preserved):

And following is what I get in log on Acer A500 (Android 3.1). Just select this Wallpaper for preview and then press Back button in preview activity (only related log entries preserved):

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的问题跟踪这两个问题(<一个href=\"http://$c$c.google.com/p/android/issues/detail?id=19243&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars\"相对=nofollow> 19243 ,<一个href=\"http://$c$c.google.com/p/android/issues/detail?id=19245&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars\"相对=nofollow> 19245 ),但实际上它是更有趣知道如何解决这些问题的机器人已经发布的版本。这就是为什么我问这里的解决方案可能会有人知道。虽然我已经在自己的解决方法(可能会是有益的,以某人的)我也想知道另外一个可能性,争取这些问题。

I have reported both these issues in Android issues tracker (19243, 19245) but practically it is more interesting to know how to resolve these issues for already released versions of Androids. This is why I am asking here for solutions anyone may know. And while I have already the own workarounds (may be will be usefull to someones) I also want to know another possibilities to fight these issues.

先谢谢了。

推荐答案

有可并行执行多个引擎。你必须对它们进行管理。要对此进行检查,只需添加一个id在每次创建引擎。你可以用这种方式验证这一点:

There are more than one engine can be executed in parallel. You have to manage them. To check this, just add an id to every engine you create. You can verify this in this way:

public class LWService extends WallpaperService {

    static int engineCounter;

    /** 
     * Will show the bug with calling {@link #onSurfaceCreated(SurfaceHolder)} 
     * and other surface callbacks after {@link #onDestroy()}. 
     *  
     */ 
    private class LWEngineTest1 extends Engine {

        public int id;

        public LWEngineTest1()
        {
          id=++engineCounter;
        }

        /** 
         * 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() engineId="+id); 
        } 

        @Override 
        public void onDestroy() { 
            logD("onDestroy() engineId="+id); 
            mAlreadyDestroyed = true;
        } 

        @Override 
        public void onSurfaceCreated(SurfaceHolder holder) {
            logD("onSurfaceCreated() engineId="+id); 
            if (mAlreadyDestroyed) {
                logE("onSurfaceCreated() after onDestroy()"); 
            } 
        } 

        @Override 
        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            logD("onSurfaceChanged() engineId="+id); 
            if (mAlreadyDestroyed) {
                logE("onSurfaceChanged() after onDestroy()"); 
            } 
        } 

        @Override 
        public void onSurfaceDestroyed(SurfaceHolder holder) {
            logD("onSurfaceDestroyed() engineId="+id); 
            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(); 
    } 
} 

我注意到,在不同设备上有略微不同的行为。所以我建议你测试在不同的设备解决方案。

I notice that on different devices there are slightly different behaviours. So i suggest you to test your solution on different devices.

这篇关于Android的WallpaperService.Engine的问题,需要的解决方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆