Android中View not attached to window manager错误的解决办法

HILINK在运行的时候,有时会出现界面弹框消失的时候,程序崩溃现象,LOG如下,

FATAL EXCEPTION: main

Process: com.huawei.mw, PID: 10185

java.lang.IllegalArgumentException: View not attached to window manager

at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:389)

at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:318)

at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:84)

at android.app.Dialog.dismissDialog(Dialog.java:331)

at android.app.Dialog.dismiss(Dialog.java:314)

at com.huawei.mw.plugin.app.activity.AppManagerActivity$1.handleMessage(AppManagerActivity.java:171)

at android.os.Handler.dispatchMessage(Handler.java:98)

at android.os.Looper.loop(Looper.java:157)

at android.app.ActivityThread.main(ActivityThread.java:5356)

原因是当Dialog调用dismiss方法的时候,WindowManager检查发现Dialog所属的Activity因为某种原因已经被杀掉,在依赖的activity上removeView的时候就会报上面的异常。

Android源码如下

void dismissDialog() {

        if (mDecor == null || !mShowing) {

            return;

        }

        if (mWindow.isDestroyed()) {

            return;

        }

        try {

            //此时Dialog所依赖的activity已经销毁,执行到此句就会出现崩溃

            mWindowManager.removeViewImmediate(mDecor);

        }  

        。。。。。。

。。。。。。 

}

修改此问题的第一个方法是,在调用dialog.dismiss()的是时候对当前的activity进行判断,如果isfinish为true则不调用dialog.dismiss(),在activity的onDestroy()中对弹框资源回收。

重点介绍第二种方法:Activity有相应的操作对话框的回调,比如showDialog,onCreateDialog(),dimissDialog(),removeDialog()等等,这些都是Activity的方法,用起来比较方便,一切都由框架操作,相对来说比较安全。

另外就是一定要让对话框对象在Activity的可控制范围之内和生命周期之内,比如一定要是它的成员变量,并且在让对话框变量活跃在Activity的onCreate()和onDestroy()之间。

举个简单的例子如下:

Class DemoDialog {

final int DIALOG_ID = 0;

private Dialog demoDialog;

@Override

public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button button = (Button) this.findViewById(R.id.Button01);
        button.setOnClickListener (new View.OnClickListener()

        {

            @Override 

            public void onClick(View v)

           {

              showDialog(final int DIALOG_ID);                  

           }

        }); 

}      
       @Override
    public Dialog onCreateDialog(int id)
    {
        if(id == DIALOG_ID)
        {

demoDialog = new ProgressDialog(this);
demoDialog.setTitle(R.string.title);//设置标题

demoDialog.setCancelable(false);      

  }       
        return demoDialog;
    }  

Android SDK 源代码如下:

public final void showDialog(int id) {
    showDialog(id, null);
}
public final boolean showDialog(int id, Bundle args) {
    if (mManagedDialogs == null) {
        mManagedDialogs = new SparseArray<ManagedDialog>();
    }
    ManagedDialog md = mManagedDialogs.get(id);
    if (md == null) {
        md = new ManagedDialog();
                 md.mDialog = createDialog(id, null, args);
        if (md.mDialog == null) {
            return false;
        }
        mManagedDialogs.put(id, md);
    }
    md.mArgs = args;
    onPrepareDialog(id, md.mDialog, args);
    md.mDialog.show();
    return true;

}

private Dialog createDialog(Integer dialogId, Bundle state, Bundle args) {
    final Dialog dialog = onCreateDialog(dialogId, args);
    if (dialog == null) {
        return null;
    }
    dialog.dispatchOnCreate(state);
    return dialog;
}

由上面的代码可以看出,我们自己创建的demoDialog的对象引用值传递给了Activity中自带的md.mDialog变量,当Activity销毁的时候,会调用onDestroy方法,android源码如下:

protected void onDestroy() {

if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);

        mCalled = true;

        // dismiss any dialogs we are managing.

        if (mManagedDialogs != null) {

            final int numDialogs = mManagedDialogs.size();

            for (int i = 0; i < numDialogs; i++) {

                final ManagedDialog md = mManagedDialogs.valueAt(i);

                if (md.mDialog.isShowing()) {

/*当activity销毁的时候,因为demoDialog和md.mDialog指向内存中的同一对象,此时demoDialog也会在当前的activity中dismiss()掉,当前弹框的isShowing值变为false*/

                    md.mDialog.dismiss();

                }

            }

            mManagedDialogs = null;

        }

}

我们回过头来看之前的dismissDialog()函数

void dismissDialog() {

    /*当弹框在activity中自带的onDestroy中dimiss后,mShowing为false,如果开发人员再次调用demoDialog.dimiss()方法的时候直接return,就不会出现之前的崩溃问题。*/

        if (mDecor == null || !mShowing) {

            return;

        }

        。。。。。。

。。。。。。 

}

原文地址:https://www.cnblogs.com/zhangkefan/p/4479533.html