Android 安卓&x27;壁纸服务。引擎问题,需要解决方法

Android 安卓&x27;壁纸服务。引擎问题,需要解决方法,android,live-wallpaper,Android,Live Wallpaper,在开发实时壁纸的过程中,我遇到了两个问题,希望找到最好的解决办法 问题1:wallperservice.Engine.onSurfaceCreated()和wallperservice.Engine.onSurfaceChanged()在wallperservice.Engine.onstroyed()之后调用 在某些情况下,在调用wallperservice.Engine.onSurfaceCreated()和wallperservice.Engine.onSurfaceChanged()之后

在开发实时壁纸的过程中,我遇到了两个问题,希望找到最好的解决办法

问题1:
wallperservice.Engine.onSurfaceCreated()
wallperservice.Engine.onSurfaceChanged()
wallperservice.Engine.onstroyed()之后调用
在某些情况下,在调用
wallperservice.Engine.onSurfaceCreated()
wallperservice.Engine.onSurfaceChanged()
之后,Android调用
wallperservice.Engine.onstroyed()
。它违反了文档定义的服务引擎执行协议

我目前的解决方案是使用显式标志(
mAlreadyDestroyed
),默认情况下该标志为false,但在
onDestroy()
回调中设置为true。
wallperservice.Engine.onSurfaceCreated()
wallperservice.Engine.onSurfaceChanged()
检查此标志,如果为真,则不执行任何操作。有人也面临过这个问题吗?你是如何解决的

以下是您可以用来检查此问题的简单代码:

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();
    }
}
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();
    }
}
以下是我在三星Galaxy S(Android 2.2.1)上的日志。只需将此示例墙纸设置为当前墙纸,然后选择另一个(仅保留相关日志条目):

问题2:
wallperservice.Engine.onsurfacedestromed()
在曲面实际销毁后调用 在某些情况下,Android可能会在surface被实际销毁后调用
wallperservice.Engine.onSurfaceDestructed()
。它违反了
SurfaceHolder.Callback.onsurfacedestromed()
规范。这个问题相当具体,即使在代码中出现,也可能会被忽略。如果有单独的渲染线程,您最多会注意到这个问题。渲染线程甚至在主应用程序的线程接收到所提到的
wallperservice.Engine.onsurfacedestromed()
之前,也可能会注意到死掉的曲面。在我的OpenGL渲染中,当执行
eglSwapBuffers()
时,我刚刚得到了EGL\u BAD\u NATIVE\u窗口

我目前的解决方案只是忽略指定的EGL错误,但我真的不喜欢这种解决方案。我的代码中充满了自检断言和错误条件检查,我不喜欢删除这些断言和检查(忽略特定的错误代码就是这样的事情)。是否存在解决此问题的方法

以下是您可以用来检查此问题的简单代码:

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();
    }
}
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(安卓3.1)上的日志。只需选择此壁纸进行预览,然后在预览活动中按“后退”按钮(仅保留相关日志条目):

我已经在Android问题跟踪(,)中报告了这两个问题,但实际上,更有趣的是知道如何为已经发布的Android版本解决这些问题。这就是为什么我在这里寻求任何人都可能知道的解决方案。虽然我已经有了自己的解决办法(可能对某些人有用),但我也想知道解决这些问题的另一种可能性


提前感谢。

我在一台运行出色的Cynagen 7.0.3(姜饼2.3.3)上试用了您的代码。我看不出你看到的问题

以下是我通过Picker>Preview>Set Wallpaper后的日志结果:

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: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()
然后,在设置完全无关的墙纸后,该实例将被销毁:

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>Preview>Back(未设置壁纸)之后的结果:


有多个引擎可以并行执行。你必须管理它们。要检查这一点,只需为您创建的每个引擎添加一个id。您可以通过以下方式进行验证:

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

我注意到,在不同的设备上,行为略有不同。因此,我建议您在不同的设备上测试您的解决方案。

对不起,没有。不过我可能会在其他时间测试。