一个少见的线上 Crash 分析:Caused by: java.lang.IllegalStateException: View DecorView@2918947[RoomManageActivi

Take the Dialog for example.

Judge from the Android source code, let’s watch what happened when you called method Dialog#show() method. The code can be simplified as below:

    public void show() {
        if (mShowing) {
            // ...
            return;
        }
        // ...
        mDecor = mWindow.getDecorView();
        mWindowManager.addView(mDecor, l);
        // ...
        mShowing = true;
        // ...
    }

The mDecor field was got from mWidnow, the mWindow field was got from Dialog's construcor:

    Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        // ...
        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        // ...
    }

So that means one Dialog has one mWindow, one mWindow has one mDecor.

When the mWindowManager.addView(mDecor, l) was called, it went to the WindowManagerGlobal#addView().

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        // ...
        synchronized (mLock) {
            // ...
            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    mRoots.get(index).doDie();
                } else {
                    // EXCEPTION HERE!!!
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
            }
            // ...
        }
    }

The WindowManagerGlobal was singleton, so that means if you add the same view to WindowManagerGlobal twice, it will crash.

We can reprocedure this exception:

val dlg = AlertDialog.Builder(context).create()
dlg.setView(View.inflate(context, R.layout.layout_dialog_title_sample, null))
dlg.show()
val f = Dialog::class.java.getDeclaredField("mShowing")
f.isAccessible = true
f.setBoolean(dlg, false)
dlg.show()

Above, we change the the field mShowing after the Dialog#show() was called to show the dialog ‘twice’. And finally it throws the exception:

    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, me.shouheng.suix.SampleApp$customCrash$1.onCrash(SampleApp.kt:64)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ ************* uncaught exception *************
    │ Time Of Crash      : 2020-01-10 14-46-43
    │ Device Manufacturer: OnePlus
    │ Device Model       : ONEPLUS A6000
    │ Android Version    : 9
    │ Android SDK        : 28
    │ App VersionName    : 1.0
    │ App VersionCode    : 1
    │ 
    │ java.lang.IllegalStateException: View DecorView@3a84c11[MainActivity] has already been added to the window manager.
    │ 	at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:328)
    │ 	at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:94)
    │ 	at android.app.Dialog.show(Dialog.java:329)
    │ 	at me.shouheng.suix.MainActivity$doCreateView$7.onClick(MainActivity.kt:72)
    │ 	at android.view.View.performClick(View.java:6669)
    │ 	at android.view.View.performClickInternal(View.java:6638)
    │ 	at android.view.View.access$3100(View.java:789)
    │ 	at android.view.View$PerformClick.run(View.java:26145)
    │ 	at android.os.Handler.handleCallback(Handler.java:873)
    │ 	at android.os.Handler.dispatchMessage(Handler.java:99)
    │ 	at android.os.Looper.loop(Looper.java:193)
    │ 	at android.app.ActivityThread.main(ActivityThread.java:6898)
    │ 	at java.lang.reflect.Method.invoke(Native Method)
    │ 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
    │ 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

So the final resolution of solving this problem was to check if you showed dialog twice exceptially in different thread.

你可能感兴趣的:(异常记录)