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;

        }

        。。。。。。

。。。。。。 

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM