bilibili / DanmakuFlameMaster

Android开源弹幕引擎·烈焰弹幕使 ~
http://app.bilibili.com/
Apache License 2.0
9.54k stars 2.1k forks source link

严格模式下一旦GC就会抛出资源未关闭错误 #376

Open IceDcap opened 6 years ago

IceDcap commented 6 years ago
06-05 16:28:22.385 17903-17912/***** E/StrictMode: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
    java.lang.Throwable: Explicit termination method 'dispose' not called
        at dalvik.system.CloseGuard.open(CloseGuard.java:180)
        at android.view.DisplayEventReceiver.<init>(DisplayEventReceiver.java:65)
        at android.view.Choreographer$FrameDisplayEventReceiver.<init>(Choreographer.java:842)
        at android.view.Choreographer.<init>(Choreographer.java:224)
        at android.view.Choreographer.<init>(Choreographer.java)
        at android.view.Choreographer$1.initialValue(Choreographer.java:121)
        at android.view.Choreographer$1.initialValue(Choreographer.java:116)
        at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:160)
        at java.lang.ThreadLocal.get(ThreadLocal.java:150)
        at android.view.Choreographer.getInstance(Choreographer.java:249)
        at master.flame.danmaku.controller.DrawHandler.updateInChoreographer(DrawHandler.java:476)
        at master.flame.danmaku.controller.DrawHandler.handleMessage(DrawHandler.java:281)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.os.HandlerThread.run(HandlerThread.java:61)
IceDcap commented 6 years ago

尝试在退出时显示的调用Choreographer的静态方法releaseInstance将不会产生警告信息sending message to a Handler on a dead thread以及上述严格模式抛出的dispose not called的问题,具体代码如下

case QUIT:
                if (what == QUIT) {
                    removeCallbacksAndMessages(null);
                }
                quitFlag = true;
                syncTimerIfNeeded();
                pausedPosition = timer.currMillisecond;
                if (mUpdateInSeparateThread) {
                    notifyRendering();
                    quitUpdateThread();
                }
                if (mFrameCallback != null) {
                    if (Build.VERSION.SDK_INT >= VERSION_CODES.N) {
                        Choreographer.getInstance().removeFrameCallback(mFrameCallback);
                        try {
                            Method method = Choreographer.class.getMethod("releaseInstance");
                            method.invoke(null);
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    } else if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN){
                        Choreographer.getInstance().removeFrameCallback(mFrameCallback);
                        Choreographer old = Choreographer.getInstance();

                        try {
                            Field sThreadInstance = Choreographer.class.getDeclaredField("sThreadInstance");
                            sThreadInstance.setAccessible(true);
                            ThreadLocal<Choreographer> instance = (ThreadLocal<Choreographer>)sThreadInstance.get(null);
                            instance.remove();
                            Field field = Choreographer.class.getDeclaredField("mDisplayEventReceiver");
                            field.setAccessible(true);
                            Object object = field.get(old);
                            Method method = object.getClass().getMethod("dispose");
                            method.invoke(object, null);
                        } catch (NoSuchFieldException e) {
                            e.printStackTrace();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        } catch (NullPointerException e) {
                            e.printStackTrace();
                        }
                    }
                }
                if (what == QUIT){
                    if (this.drawTask != null){
                        this.drawTask.quit();
                    }
                    if (mParser != null) {
                        mParser.release();
                    }
                    if (this.getLooper() != Looper.getMainLooper())
                        this.getLooper().quit();
                }
                break;