java.lang.IllegalArgumentException: View not attached to window manager when dismissing dialog

來源:互聯網
上載者:User

Exception One,
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:664)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:354)
at android.view.WindowManagerImpl$CompatModeWrapper.removeView(WindowManagerImpl.java:165)
at android.app.Dialog.dismissDialog(Dialog.java:319)
at android.app.Dialog.dismiss(Dialog.java:302)
at com.android.email.activity.setup.AccountSetupBasics$FindProviderTask.onPostExecute(AccountSetupBasics.java:914)
at com.android.email.activity.setup.AccountSetupBasics$FindProviderTask.onPostExecute(AccountSetupBasics.java:863)
at android.os.AsyncTask.finish(AsyncTask.java:631)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4780)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:808)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:575)
at dalvik.system.NativeStart.main(Native Method)

Exception Two,
STACK TRACE:
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:355)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:200)
at android.view.Window$LocalWindowManager.removeView(Window.java:432)
at android.app.Dialog.dismissDialog(Dialog.java:280)
at android.app.Dialog.access$000(Dialog.java:73)
at android.app.Dialog$1.run(Dialog.java:109)
at android.app.Dialog.dismiss(Dialog.java:264)
at com.xxxxxxxx.suquashi.ActionDialog.access$001(ActionDialog.java:43)
at com.xxxxxxxx.suquashi.ActionDialog$2.onAnimationEnd(ActionDialog.java:299)
at android.view.animation.AnimationSet.getTransformation(AnimationSet.java:329)
at android.view.ViewGroup.drawChild(ViewGroup.java:1494)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1356)
at android.view.ViewGroup.drawChild(ViewGroup.java:1627)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1356)
at android.view.ViewGroup.drawChild(ViewGroup.java:1627)

[Bad Design]
The following code is a bad design to put dialog.dismiss() and activity.finish() in the asynctask.

final AsyncTask<MyParams, Object, MyResult> task = new AsyncTask<MyParams, Object, MyResult>() {    @Override    protected MyResult doInBackground(MyParams... params) {        // Long operation goes here    }    @Override    protected void onPostExecute(MyResult result) {        dialog.dismiss();        onCompletion(result);  finish();    }};

First every dialog or sth extends dialog would have a own window and décor view(itself), and except popup(dialog) there is a window and décor view. Second when the phone change orientation, the activity Thread would call HandleRelaunchActivity(this would call handledestroyactivity), the window manager would remove all the window and décor view and then create new window and décor, so the old décor has no use after this had been done.
In the code of action dialog there would be a animation make the super dismiss called later, but if the HandleRelaunchActivity happened, the actiondialog's décor would be useless, then the animation call back come, the super dismiss is called, it should not be in the mview[] in windowmanagerimpl. After that analyze, I think if this happened, we don't have very useful method to prevent, and it should be ok for a not in the array, but if lockview method throw a exception, I think we could just catch it. It won't affect much because the décor view(actiondialog) would be useless.

Change affects the way the ActionDialog behaves when it is dismissed. Most notable for an end user is that an ActionDialog that is closed when its Activity is being shut down will no longer animate.

Addition to the information below The reason for the Dialog being removed from WindowManager in the first place is typically due to a rotation of the screen, and if the ActionDialog is managed the Android system will take care of removing/dismissing it.

The problem seems to be because ActionDialog delays Dialog.dismiss() to play an animation. When the animation is finished ActionDialog calls Dialog.dismiss but at that time it has already been removed from the WindowManager so the WindowManager will throw an exception when Dialog requests to be removed from WindowManager.

This problem is thus related to ActionDialog and not HomeScreen which means that other applications using ActionDialog could also get this problem. I have seen one MTBF-crash for com.sonyericsson.contacts and one for Timescape due to this.

It could be wrong here, but I suspect that multiple phones 'in the wild' have a bug that causes them to switch orientation on applications that are marked as statically oriented. This happens quite a bit on my personal phone, and on many of the test phones our group uses (including droid, n1, g1, hero). Typically an app marked as statically oriented (perhaps vertically) will lay itself out for a second or two using a horizontal orientation, and then immediately switch back. End result is that even though you don't want your app to switch orientation, you have to be prepared that it may. I don't know under what exact conditions this behavior can be reproduced, I don't know if it is specific to a version of Android. All I know is that I have seen it happen plenty of times

I would recommend using the solution provided in the link you posted that suggests overriding the Activity onCreateDialog method and letting the Android OS manage the lifecycle of your Dialogs. It looks to me like even though you don't want your activity to switch orientations, it is switching orientation somewhere. You can try to track down a method that will always prevent orientation switching, but I am trying to tell you that I personally don't believe there is a foolproof way that works on all current Android phones in the market.

[Dialog dismiss Framework Code]

301    public void dismiss() {302        if (Thread.currentThread() != mUiThread) {303            mHandler.post(mDismissAction);304        } else {305            mHandler.removeCallbacks(mDismissAction);306            mDismissAction.run();307        }308    }

For Exception One, In email, IllegalArgumentException rises in onPostExec when the AsyncTsk is finishing.
When dismissing the dialog, WindowManager can't find the window and view in its Views.   

300    public void dismiss() {301        if (Looper.myLooper() == mHandler.getLooper()) {302            dismissDialog();303        } else {304            mHandler.post(mDismissAction);305        }306    }307308    void dismissDialog() {309        if (mDecor == null || !mShowing) {310            return;311        }312313        if (mWindow.isDestroyed()) {314            Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!");315            return;316        }317318        try {319            mWindowManager.removeView(mDecor);320        } finally {321            if (mActionMode != null) {322                mActionMode.finish();323            }324            mDecor = null;325            mWindow.closeAllPanels();326            onStop();327            mShowing = false;328329            sendDismissMessage();330        }331    }158        @Override159        public void removeView(View view) {160   if(null == view)161   {162             Log.d("WindowManager", "uuNote:removeView:view=null###");163    throw new NullPointerException("view parameter is NULL into findViewLocked()");164   }165            mWindowManager.removeView(view);166        }352    public void removeView(View view) {353        synchronized (this) {354            int index = findViewLocked(view, true);355            View curView = removeViewLocked(index);356            if (curView == view) {357                return;358            }359360            throw new IllegalStateException("Calling with view " + view361                    + " but the ViewAncestor is attached to " + curView);362        }363    }649    private int findViewLocked(View view, boolean required) {650        synchronized (this) {651            final int count = mViews != null ? mViews.length : 0;652            for (int i=0; i<count; i++) {653                if (mViews[i] == view) {654                    return i;655                }656            }657            if(null==view)658            {659             Log.d("WindowManager", "findViewLocked:view=null###");660             required = false;661  throw new NullPointerException("view parameter is NULL into findViewLocked()");662            }663            if (required) {664                throw new IllegalArgumentException(665                        "View not attached to window manager");666            }667            return -1;668        }669    }670}

[Reference Solution]
Move the dialog.dismiss() and activity.finish to UiThread.

 new Thread() {  2946   @Override  2947   public void run() {  2948    Uri uri = ContentUris.withAppendedId(SemcThreads.CONTENT_URI,  2949       threadId);  2950    getContentResolver().delete(uri, null, null);  2951    runOnUiThread(new Runnable() {  2952     public void run() {  2953      pd.dismiss();  2954            2955      // prevent saving of draft  2956      mComposer = null;  2957      mConversation = null;  2958            2959      Notifications.updateAll(ConversationActivity.this);  2960      ConversationCache.clear();  2961      finish();  2962     }  2963    });  2964   }  2965  }.start();  

if you use many dialogs, should close all dialog in activity's overriden onDestroy() or onStop().
then you may be able to reduce the frequency 'java.lang.IllegalArgumentException: View not attached to window manager' exception occurs.

@Overrideprotected void onDestroy() {    Log.d(TAG, "called onDestroy");    mDialog.dismiss();    super.onDestroy();}

but little exceed...
to make it more clear, you prevent to show any dialog after onDestroy called.
i don't use as below. but it's clear.

private boolean mIsDestroyed = false;private void showDialog() {    closeDialog();    if (mIsDestroyed) {        Log.d(TAG, "called onDestroy() already.");        return;    }    mDialog = new AlertDialog(this)        .setTitle("title")        .setMessage("This is DialogTest")        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {            public void onClick(DialogInterface dialog, int which) {                dialog.dismiss();            }        })        .create();    mDialog.show();}private void closeDialog() {    if (mDialog != null && mDialog.isShowing()) {        mDialog.dismiss();    }}@Overrideprotected void onDestroy() {    Log.d(TAG, "called onDestroy");    mIsDestroyed = true;    closeDialog();    super.onDestroy();}

And at last, is it better to use dialog.cancel() rather than dialog.dismiss()?
 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.