Activity在后台被回收,这个时候触发showDialog,窗体泄露,WindowManager.BadTokenException

今天在友盟上看到一个崩溃日志,如下:

android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@4394f040 is not valid; is your activity running?
	at android.view.ViewRootImpl.setView(ViewRootImpl.java:798)
	at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:288)
	at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:73)
	at android.app.Dialog.show(Dialog.java:287)
	at com.module.exam.ExamActivity$1.onTimeCountFinished(ExamActivity.java:71)
	at com.module.question.QuestionBaseActivity$5.onTimeCountFinished(QuestionBaseActivity.java:324)
	at com.utils.TimeCount.onFinish(TimeCount.java:49)
	at android.os.CountDownTimer$1.handleMessage(CountDownTimer.java:118)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at android.os.Looper.loop(Looper.java:137)
	at android.app.ActivityThread.main(ActivityThread.java:5493)
	at java.lang.reflect.Method.invokeNative(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:525)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
	at dalvik.system.NativeStart.main(Native Method)
问题原因在于,我的ExamActivity是一个拥有CountDownTimer组件来执行倒计时业务的对象,该对象源码实现可以看到是通过消息队列机制,sendMessageDelay(msg,time)来实现的,所以就有一种情况,考试ExamActivity 在后台运行,这个时候Timer还在执行倒计时,一段时间后,考试ExamActivity被系统回收掉了,倒计时还在执行,当倒计时完成后触发 onTimerFinish()方法, 这个时候如果dialog.show() 就会报该错误。是因为这个时候window与Activity分离了,造成了窗体泄露。


解决方法:  

                      1.  判断当前Activity是否finish()了通过  isFinishing()

                      2.  在show时,捕获异常

示例代码如下

setTimeCountListener(new TimeCount.OnTimeCountListener() {
            @Override
            public void onTimeCountFinished() {
                if(!ExamActivity.this.isFinishing()){
                    final TipsDialog tipsDialog = new TipsDialog(ExamActivity.this);
                    tipsDialog.oneBtn("答题时间已到,本次考试结束,请交卷", "交卷", new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            tipsDialog.dismiss();
                            endExam();
                        }
                    });
                    try {
                        tipsDialog.show();
                    }catch (WindowManager.BadTokenException e){
                        LogUtil.e(e.toString());
                    }
                }
            }

这样就保证了不会发生类似错误了。

总结:

         当程序中有类似 postMessageDelay 这种控制dialog显示的情况时,一定要考虑到Activity被回收这种情况。另外看Activity源码  onDestory里判断所有还在运行的dialog都会被主动销毁。这是另外一个问题。

        

         

      




你可能感兴趣的:(Activity在后台被回收,这个时候触发showDialog,窗体泄露,WindowManager.BadTokenException)