IllegalStateException: view has already been added to the window manager
Asked Answered
E

3

12

I have spent hours trying to fix an app crash and I think it deserves a question:

The Exception:

java.lang.IllegalStateException: View android.widget.LinearLayout{41a97eb8 V.E..... ......ID 0,0-540,105 #7f0b020d app:id/toast_layout_root} has already been added to the window manager.
   at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:223)
   at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
   at android.widget.Toast$TN.handleShow(Toast.java:402)
   at android.widget.Toast$TN$1.run(Toast.java:310)
   at android.os.Handler.handleCallback(Handler.java:730)
   at android.os.Handler.dispatchMessage(Handler.java:92)
   at android.os.Looper.loop(Looper.java:137)
   at android.app.ActivityThread.main(ActivityThread.java:5136)
   at java.lang.reflect.Method.invokeNative(Method.java)
   at java.lang.reflect.Method.invoke(Method.java:525)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
   at dalvik.system.NativeStart.main(NativeStart.java)

The Code:

I have a custom toast following this guide

I defined the custom toast as ToastMessageBar.java and the constructor looks like this:

public ToastMessageBar(Activity activity) {
    LayoutInflater inflater = activity.getLayoutInflater;
    mToastLayout = inflater.inflate(R.layout.toast_layout,
            (ViewGroup) activity.findViewById(R.id.toast_layout_root));

    mMessageView = (TextView) mToastLayout.findViewById(R.id.toast_message);
    mSubtitleView = (TextView) mToastLayout.findViewById(R.id.toast_subtitle);
}

and the way I show a toast message is following:

private void showMessage(MessageType type, String message, String subtitle) {
    int duration = Toast.LENGTH_SHORT;
    if (mToastLayout != null) {
        int colorId;
        switch (type) {
            case Warning:
                colorId = R.color.warning_bar_color;
                duration = Toast.LENGTH_SHORT;
                break;

            case Error:
                colorId = R.color.error_bar_color;
                break;

            default:
                colorId = R.color.info_bar_color;
                break;
        }

        mToastLayout.setBackgroundColor(
                MyApp.getContext().getResources().getColor(colorId));

        if (subtitle == null) {
            mMessageView.setVisibility(View.GONE);
            mSubtitleView.setText(message);
        } else {
            mMessageView.setVisibility(View.VISIBLE);
            mMessageView.setText(message);
            mSubtitleView.setText(subtitle);
        }
    }

    Utils.showToast(mToastLayout, message, duration);
}

public static void showToast(View layout, String message, int duration) {
    if (layout != null) {
        Toast toast = new Toast(MyApp.getContext());
        toast.setGravity(Gravity.TOP|Gravity.FILL_HORIZONTAL, 0, 0);
        toast.setDuration(duration);
        toast.setView(layout);
        toast.show();
        return;
    }

    Toast.makeText(MyApp.getContext(), message, Toast.LENGTH_LONG).show();
}

In MyBaseActivity.onCreate() I define the ToastMessageBar:

mMessageBar = new ToastMessageBar(this);

In this way, I can use showMessage() in all the activities that inherits MyBaseActivity.

It seems the exception happens when I call toast.show(); but it does not happen all the time (only rare cases) I don't know what caused the exception still.

Erysipeloid answered 10/3, 2015 at 6:9 Comment(3)
At which line you got error? can you paste that line?Cilicia
@PratikPopat toast.show()Erysipeloid
I have the same exact problem. I am also keeping mToast as the activity class member. Have you found your way around it? I will try to debug and might come back later.Tinatinamou
B
3

First off- when you're asking for help on an exception, always give us the full stack trace.

You're screwing up with your inflation and Toast usage. When you use the layout the first time, you're cool. The second time, it already has a parent (the Toast), so it will throw an error when you try to add it to the toast via setView. You either need to inflate a new copy each Toast, or remove it from the old Toast before adding it to the new one.

Bloomsbury answered 10/3, 2015 at 6:18 Comment(5)
if you check the code of Toast.java handleShow(), it has the checking of whether the view already has parent if (mView.getParent() != null) { if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); mWM.removeView(mView); } if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this); mWM.addView(mView, mParams);Erysipeloid
and because this crash does not happen locally, I only get limited info from CrashlyticsErysipeloid
You're counting on an implementation detail like that? Sure it does that in every version of Android ever released? Because the exception you have is exactly what I said- you try to add a view to a window for a second time.Bloomsbury
Ok, I get your point. so what should be the right way of handling that?Erysipeloid
I checked the crash records, all of them are from Android 4.3Erysipeloid
B
1

You'd better set a new view every time you want to show the Toast.

In Toast.java handleHide() function. It says:

            // note: checking parent() just to make sure the view has
            // been added...  i have seen cases where we get here when
            // the view isn't yet added, so let's try not to crash.
            if (mView.getParent() != null) {
                if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                mWM.removeView(mView);
            }

And in Toast.java handleShow() function

            if (mView.getParent() != null) {
                if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                mWM.removeView(mView);
            }
            if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
            mWM.addView(mView, mParams);

May be when the last view been added but don't have a parent yet. A new view comes. Then it throw IllegalStateException

Barram answered 24/9, 2015 at 2:36 Comment(0)
C
0

I think problem at this line

   mToastLayout = inflater.inflate(R.layout.toast_layout,
            (ViewGroup) activity.findViewById(R.id.toast_layout_root));

Instead try:

mToastLayout = inflater.inflate(R.layout.toast_layout,null);
Cilicia answered 10/3, 2015 at 6:36 Comment(1)
check the link here developer.android.com/guide/topics/ui/notifiers/toasts.html I'm following this.Erysipeloid

© 2022 - 2024 — McMap. All rights reserved.