IllegalStateException: view has already been added to the window manager

xialin picture xialin · Mar 10, 2015 · Viewed 13.6k times · Source

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.

Answer

Gabe Sechan picture Gabe Sechan · Mar 10, 2015

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.