android.view.WindowManager $ BadTokenException:无法添加窗口-在Toast

时间:2018-10-04 14:34:35

标签: android toast

当我在我的android应用上频繁执行某些操作时(我的假设,这是由于Toast消息引起的),出现以下错误。我没有确切找到此问题的位置。我可以从某人那里寻求帮助来解决该问题吗?< / p>

 --------- 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) 

注意:这种崩溃并不总是会出现。

4 个答案:

答案 0 :(得分:4)

在将Context传递到Toast之前,应始终检查要使用的上下文的有效性。在我的应用程序中,我使用了一种上下文检查器方法:

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());
}

您只能传递一个上下文,如果当前上下文是一个片段,也可以传递Fragment。此方法检查上下文是否为Activity,在这种情况下,我们检查活动是否已完成/销毁。

如果要在片段生命周期之后显示吐司,还可以传递到当前片段的方法,这样我们就可以判断该片段是否仍然可见并附加到活动中。

BANDUS ANDROID 7.1

在API 25上,这还不够,有时设备仍会因您提供的堆栈跟踪而崩溃。

This repository可能是解决方案,因为它将错误的调用包装在try / catch子句中。当然,这不是最好的做法,但至少可以解决7.1设备的这种令人讨厌的崩溃。

答案 1 :(得分:0)

  

android.view.WindowManager $ BadTokenException:无法添加窗口-令牌android.os.BinderProxy@e2815e无效;您的活动正在进行吗?

在此行中,它向您提示您在尝试举杯时可能没有进行活动。

如果要在这样的活动中显示吐司,

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

您应该意识到,您试图通过将第一个参数设置为'this'并以此方式(如果您finish())将其显示在Activity的上下文中;您在此行之前的活动,您将获得该异常。因此,我建议检查是否是这种情况,或者您可以改用Application的上下文:

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

希望这会有所帮助!

答案 2 :(得分:0)

这是Toast在Android 8.0之后正式修复的问题,也可以通过将WindowManagerWrapper.addView(view, params)与第三方lib PureWriter/ToastCompat挂钩来解决。

由于isFinishing是异步进度,因此检查活动Toast.show()无法解决崩溃问题:

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

在Android 8.0之后,崩溃被捕获在handleShow中(请参阅最后几行):

        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 */
                }
            }
        }

答案 3 :(得分:0)

尝试使用应用程序上下文,而不是活动上下文。


更新: 抱歉,无论您传递给Toast的上下文是Activity还是ApplicationContext或Service,都会发生此异常。而且您无法尝试捕获它。

无法解决它,这是API 25上的一个Android SDK错误。 尝试编写一个新的Toast类。