android.view.WindowLeaked 的错误问题

09-17 23:03:38.954: E/WindowManager(1994): android.view.WindowLeaked: Activity app.ui.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{b2d3d4e0 V.E..... R.....I. 0,0-280,139} that was originally added here
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.ViewRootImpl.(ViewRootImpl.java:348)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:248)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.app.Dialog.show(Dialog.java:286)
09-17 23:03:38.954: E/WindowManager(1994): 	at app.ui.MainActivity.showExitDialog(MainActivity.java:69)
09-17 23:03:38.954: E/WindowManager(1994): 	at app.ui.MainActivity.onKeyDown(MainActivity.java:48)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.KeyEvent.dispatch(KeyEvent.java:2640)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.app.Activity.dispatchKeyEvent(Activity.java:2423)
09-17 23:03:38.954: E/WindowManager(1994): 	at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1962)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3418)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3558)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:3718)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2010)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1704)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1695)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:1987)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.os.MessageQueue.nativePollOnce(Native Method)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.os.MessageQueue.next(MessageQueue.java:138)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.os.Looper.loop(Looper.java:123)
09-17 23:03:38.954: E/WindowManager(1994): 	at android.app.ActivityThread.main(ActivityThread.java:5017)
09-17 23:03:38.954: E/WindowManager(1994): 	at java.lang.reflect.Method.invokeNative(Native Method)
09-17 23:03:38.954: E/WindowManager(1994): 	at java.lang.reflect.Method.invoke(Method.java:515)
09-17 23:03:38.954: E/WindowManager(1994): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
09-17 23:03:38.954: E/WindowManager(1994): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
09-17 23:03:38.954: E/WindowManager(1994): 	at dalvik.system.NativeStart.main(Native Method)


首先说明:这个错误不属于内存溢出,而是android中的窗体溢出。

1.Activity 的生命周期与 Dialog 的不一样 AlertDialog.Builder builder=new AlertDialog.Builder(context);

2.这个context 是Activity的上下文 

3.Dialog 要在Activity 销毁前 dismiss()掉,不然就窗体溢出

所以在解决此问题时,要判断窗体是否关闭,再干掉Activity

    /**
     * 捕获返回按钮事件
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            showExitDialog();
            return false;
        } else {
            return super.onKeyDown(keyCode, event);
        }
    }

    //退出提示
    protected void showExitDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("提示");
        builder.setMessage("您确定要退出么?");
        builder.setNegativeButton("取消", null);
        builder.setPositiveButton("退出", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                MainActivity.this.finish();
                dialog.cancel();//取消dialog,或dismiss掉
            }
        });
        if (!isFinishing()) {
            builder.create().show();
        }
    }
原因:
Android的每一个Activity都有个WindowManager窗体管理器,同样,构建在某个Activity之上的对话框、PopupWindow也有相应的WindowManager窗体管理器。但是它们不能脱离Activity而单独存在着,因为需要Activity的Context,所以当某个Dialog或者某个PopupWindow正在显示的时候我们干掉了承载该Dialog(或PopupWindow)的Activity,就会抛Window Leaked异常了,因为这个Dialog(或PopupWindow)的WindowManager已经没有谁可以附属了(Context)。


在android中常常会遇到与context有关的内容,浅论一下context : 在语句 AlertDialog.Builder builder = new AlertDialog.Builder(this); 中,要求传递的参数就是一个context,在这里传入的是this,那么这个this究竟指的是什么东东呢? 这里的this指的是Activity.this,是当前这个Activity 的上下文(Context)。

网上有很多朋友在这里传入this.getApplicationContext(),这是不对的。为什么? AlertDialog对象是依赖于一个View的,而View是和一个Activity对应的。 于是,这里涉及到一个生命周期的问题,this.getApplicationContext()取的是整个应用程序的ContextActivity.this取的是这个Activity的Context,这两者的生命周期是不同 的,前者的生命周期是整个应用,后者的生命周期只是它所在的Activity。而AlertDialog应该是属于一个Activity的,在Activity销毁的时候它也就销毁了,不会再存在;但是,如果传入this.getApplicationContext(),就表示它的生命周期是整个应用程序,这显然超过了它 的生命周期了。 

所以,在这里只能使用Activity的this。 差别就是不同的生命周期。

你可能感兴趣的:(Android技术笔记)