当我在Android应用上频繁执行某项操作(我的假设,是由于Toast消息所致)时,出现以下错误。我没有确切找到此问题的位置。我可以从某人那里寻求帮助来解决该问题吗?
--------- 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)
Run Code Online (Sandbox Code Playgroud)
注意:此崩溃并非总是会出现。
在将ContextTo 传递给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());
}
Run Code Online (Sandbox Code Playgroud)
您只能传递一个上下文,Fragment如果当前上下文是一个片段,也可以传递。此方法检查上下文是否为Activity,在这种情况下,我们检查活动是否已完成/销毁。
如果要在片段生命周期之后显示吐司,还可以传递到当前片段的方法,这样我们就可以判断该片段是否仍然可见并附加到活动中。
红利7.1
在API 25上,这还不够,有时设备仍会因您提供的stacktrace而崩溃。
该存储库可能是解决方案,因为它将错误的调用包装在try / catch子句中。当然,这并不是最好的做法,但至少可以解决7.1设备的这种令人讨厌的崩溃。
这是 Android 8.0 之后官方修复的问题Toast,也可以通过 hookWindowManagerWrapper.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
Run Code Online (Sandbox Code Playgroud)
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 */
}
}
}
Run Code Online (Sandbox Code Playgroud)
android.view.WindowManager$BadTokenException:无法添加窗口 - 令牌 android.os.BinderProxy@e2815e 无效;您的活动正在运行吗?
在这一行中,它向您提示,当您尝试显示祝酒词时,您的活动可能尚未运行。
如果您在这样的活动中展示 Toast,
Toast toast = Toast.makeText(this, R.string.message, Toast.LENGTH_LONG).show();
Run Code Online (Sandbox Code Playgroud)
您应该意识到,您正在尝试通过将第一个参数设置为“this”来在 Activity 的上下文中显示它,通过这种方式,如果您 finish(); 您在该行之前的活动,您会得到该异常。所以我建议检查是否是这种情况,或者您可以使用应用程序的上下文来代替:
Toast toast = Toast.makeText(getApplicationContext(), R.string.message, Toast.LENGTH_LONG).show();
Run Code Online (Sandbox Code Playgroud)
希望这有帮助!
| 归档时间: |
|
| 查看次数: |
1321 次 |
| 最近记录: |