10

When I do some action frequently(my assumption, is that due to Toast message) on my android app,getting below error.Im not getting exact location of this Issue.Can I get help from someone to resolve the same?

 --------- beginning of crash
10-04 16:13:49.250 6541-6541/com.test.myapp E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.test.myapp, PID: 6541
    android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@e2815e is not valid; is your activity running?
        at android.view.ViewRootImpl.setView(ViewRootImpl.java:679)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:342)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
        at android.widget.Toast$TN.handleShow(Toast.java:459)
        at android.widget.Toast$TN$2.handleMessage(Toast.java:342)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Native Method) 

Notes: This crash is not coming always.

kavie
  • 1,984
  • 3
  • 20
  • 45
  • Possible duplicate of ["android.view.WindowManager$BadTokenException: Unable to add window" on buider.show()](https://stackoverflow.com/questions/18662239/android-view-windowmanagerbadtokenexception-unable-to-add-window-on-buider-s) – ADM Oct 04 '18 at 14:44
  • That means your `Context` which you pass in creating toast is `DEAD`. Check activity state before using `Context`. – ADM Oct 04 '18 at 14:45
  • Getting the same exception even though all my Toast calls are wrapped by a method that null-checks context and also check if finishing/destroyed state (for activities) or detached state (for fragments) but it looks like it's not enough – fillobotto Oct 10 '18 at 08:32
  • Did you solve the problem? – fillobotto Mar 28 '19 at 11:39

4 Answers4

11

Before passing a Context to the Toast, you should always check the validity of the context you are going to use. In my applications, I use a context-checker method I made:

public static boolean isContextValid(Context context, Fragment fragment) {
    if (context instanceof Activity) {
        Activity activity = (Activity) context;
        if (activity.isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed())) {
            return false;
        }
    }

    return context != null && (fragment == null || (fragment.isAdded() && !fragment.isRemoving());
}

You can pass only a context, or also a Fragment if your current context is a fragment. This method checks if the context is an Activity, in this case we check if the activity is finishing/destroyed.

If you want to display the toast following fragment lifecycle, also pass to the method you current fragment, so we can tell whether the fragment is still visible and attached to the activity.

BONUS ANDROID 7.1

On API 25, this is not enough and sometimes the device still crash with the stacktrace you provided.

This repository might be the solution since it wraps the faulty call in a try/catch clause. Of course it's not the best thing to do, but at least solves this annoying crash for 7.1 devices.

fillobotto
  • 3,428
  • 5
  • 29
  • 51
3

android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@e2815e is not valid; is your activity running?

In this line, it gives you a hint that your activity might not be running at the time you are trying to show a toast.

If you are showing a Toast in an activity like this,

Toast toast = Toast.makeText(this, R.string.message, Toast.LENGTH_LONG).show();

you should be aware that you are trying to show it in the Activity's context by setting the first argument to 'this' and by this way, if you finish(); your activity before this line, you get that exception. So I suggest checking if this is the case, or maybe you can use Application's context instead:

Toast toast = Toast.makeText(getApplicationContext(), R.string.message, Toast.LENGTH_LONG).show();

Hope this is helpful!

Onur D.
  • 344
  • 2
  • 11
  • I'm passing Context reference as a first parameter.before getting Toast Crash,I'm getting Duplicate finish request for ActivityRecord{6ed6c1a u0 com.test.myapp /.activities.MyActivity t328 f}.But In this activity i'm not showing any Toast.. – kavie Oct 04 '18 at 15:02
  • If you are using any background threads (AsyncTasks, Api calls), make sure your activity is not finished or in finishing process before doing anything in its context (like manipulating the UI, showing toasts or dialogs, etc.) – Onur D. Oct 04 '18 at 15:18
3

This is an issue of Toast officially fixed after Android 8.0, and can also be fixed by hooking WindowManagerWrapper.addView(view, params) with a third party lib PureWriter/ToastCompat.

Checking activity isFinishing cannot fix the crash due to Toast.show() is an asynchronous progress:

Toast.makeText().show()
-> Toast.getService().enqueueToast()
-> Toast.TN.handleShow() // crash here, and unable to be caught from outside

After Android 8.0, the crash is caught in handleShow (See the last few lines):

        public void handleShow(IBinder windowToken) {
            if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
                    + " mNextView=" + mNextView);
            // If a cancel/hide is pending - no need to show - at this point
            // the window token is already invalid and no need to do any work.
            if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) {
                return;
            }
            if (mView != mNextView) {
                // remove the old view if necessary
                handleHide();
                mView = mNextView;
                Context context = mView.getContext().getApplicationContext();
                String packageName = mView.getContext().getOpPackageName();
                if (context == null) {
                    context = mView.getContext();
                }
                mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
                // We can resolve the Gravity here by using the Locale for getting
                // the layout direction
                final Configuration config = mView.getContext().getResources().getConfiguration();
                final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());
                mParams.gravity = gravity;
                if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
                    mParams.horizontalWeight = 1.0f;
                }
                if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
                    mParams.verticalWeight = 1.0f;
                }
                mParams.x = mX;
                mParams.y = mY;
                mParams.verticalMargin = mVerticalMargin;
                mParams.horizontalMargin = mHorizontalMargin;
                mParams.packageName = packageName;
                mParams.hideTimeoutMilliseconds = mDuration ==
                    Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
                mParams.token = windowToken;
                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);
                // Since the notification manager service cancels the token right
                // after it notifies us to cancel the toast there is an inherent
                // race and we may attempt to add a window after the token has been
                // invalidated. Let us hedge against that.
                try {
                    mWM.addView(mView, mParams);
                    trySendAccessibilityEvent();
                } catch (WindowManager.BadTokenException e) {
                    /* ignore */
                }
            }
        }
thundertrick
  • 1,264
  • 1
  • 12
  • 21
0

Try to use application context ,instead of Activity context.


Update: Sorry,This exception occurs regardless of whether the Context you passed to Toast is an Activity or ApplicationContext or Service. And you can not try-catch it.

There is no way to resolve it.It's a Android SDK bug on API 25. Try to write a new Toast class.

Leon
  • 31
  • 1
  • 5