Android P 预览中 toast View 的 IllegalStateException
IllegalStateException of toast View on Android P preview
在尝试发布我的应用程序以供生产时,预发布报告通知我 Pixel 2 Android P 预览设备上出现错误。该错误与我的自定义 toast 消息有关,表示视图 "has already been added to the window manager":
java.lang.IllegalStateException: View android.support.constraint.ConstraintLayout{efbeb21 V.E...... ......ID 0,0-788,1124 #7f0900db app:id/toast_correct_container} has already been added to the window manager.
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:328)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
at android.widget.Toast$TN.handleShow(Toast.java:499)
at android.widget.Toast$TN.handleMessage(Toast.java:403)
at android.os.Handler.dispatchMessage(Handler.java:106)
at androidx.test.espresso.base.Interrogator.a(Interrogator.java:19)
at androidx.test.espresso.base.UiControllerImpl.a(UiControllerImpl.java:142)
at androidx.test.espresso.base.UiControllerImpl.a(UiControllerImpl.java:134)
at androidx.test.espresso.base.UiControllerImpl.a(UiControllerImpl.java:34)
at androidx.test.espresso.action.MotionEvents.a(MotionEvents.java:74)
at androidx.test.espresso.action.MotionEvents.a(MotionEvents.java:52)
at androidx.test.espresso.action.Tap.c(Tap.java:9)
at androidx.test.espresso.action.Tap.a(Tap.java:19)
at androidx.test.espresso.action.Tap.b(Tap.java:2)
at androidx.test.espresso.action.GeneralClickAction.perform(GeneralClickAction.java:22)
at androidx.test.espresso.ViewInteraction$SingleExecutionViewAction.perform(ViewInteraction.java:9)
at androidx.test.espresso.ViewInteraction.a(ViewInteraction.java:78)
at androidx.test.espresso.ViewInteraction.a(ViewInteraction.java:94)
at androidx.test.espresso.ViewInteraction.call(ViewInteraction.java:3)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
在 MainActivity OnCreate 中,我调用了这个膨胀 toast View 的方法:
private void initToastObjects() {
mToastCorrect = new Toast(this);
mToastWrong = new Toast(this);
// inflate view
LayoutInflater myInflater = LayoutInflater.from(this);
mLayoutCorrect = myInflater.inflate(R.layout.toast_correct, (ViewGroup) findViewById(R.id.toast_correct_container));
mLayoutWrong = myInflater.inflate(R.layout.toast_wrong, (ViewGroup) findViewById(R.id.toast_wrong_container));
}
我后来根据用户选择动态设置了不同的图像到吐司:
mToastCorrect.setView(mLayoutCorrect);
每次用户单击 correct/wrong 个答案时我都会显示 toast 消息,如果显示了另一个 toast,则取消:
// cancel previous wrong answer toast and display correct answer toast
try {
if (mToastWrong.getView().isShown()) {
mToastWrong.cancel();
}
mToastCorrect.show();
} catch (Exception e) {
e.printStackTrace();
}
感谢任何帮助!
- 我该如何解决这个问题?
- 为什么我只在 Android P 预览设备上收到此错误?
- 如果我在 MainActivity OnCreate 期间仅对 View 充气一次,为什么我会收到错误消息说视图 "has already been added to the window manager"?
经过几次尝试和错误,我设法修复了它。希望对遇到同样问题的其他人有所帮助。
显然,toast 消息处理已在 Android P (API 28) 中更改。在我的应用程序中,toast 消息是由单击按钮触发的,因此可以在上一个 toast 消息完成之前调用 toast 消息(请注意,两个 toast 消息是从同一个 Toast
对象调用的)。在 P (API 28) 之前的 Android 版本上,在前一个 toast 完成之前开始新的 toast 没有问题(即使它是相同的 Toast
对象)——新的toast 只是覆盖旧的 toast 并重新开始。
但是,在 Android P 中,相同的行为有时可能会抛出 IllegalStateException
.
我已经保留了对 Toast 对象的引用以重用它,所以我只需要取消它以防它被显示。由于取消它会导致 API 低于 28 的不良行为(例如吐司消息在很短的时间后消失),我插入了一个版本检查。这是解决方法代码:
// cancel previous toast and display correct answer toast
try {
if (mToastWrong.getView().isShown()) {
mToastWrong.cancel();
}
// cancel same toast only on Android P and above, to avoid IllegalStateException on addView
if (Build.VERSION.SDK_INT >= 28 && mToastCorrect.getView().isShown()) {
mToastCorrect.cancel();
}
mToastCorrect.show();
} catch (Exception e) {
e.printStackTrace();
}
我仍然不解的是为什么try-catch代码没有捕捉到异常(应用程序崩溃)。
我在 Pie 上看到了相同的崩溃报告,快速触发相同的自定义 Toast(由硬件音量按钮触发)。与 OP 的用例不同的是,我只有一个自定义 Toast 实例,只有它的自定义视图正在更新。
除了这次崩溃(我无法在 Pie 模拟器中重现自己,但在崩溃报告中看到),我还有另一个问题:在同一个 toast 上快速调用 Toast.show() 时(比如,20次),充其量只有前 2 个调用显示吐司然后它消失。在显示之前取消祝酒词没有帮助。
结论,烤面包片真的碎了...
在尝试发布我的应用程序以供生产时,预发布报告通知我 Pixel 2 Android P 预览设备上出现错误。该错误与我的自定义 toast 消息有关,表示视图 "has already been added to the window manager":
java.lang.IllegalStateException: View android.support.constraint.ConstraintLayout{efbeb21 V.E...... ......ID 0,0-788,1124 #7f0900db app:id/toast_correct_container} has already been added to the window manager.
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:328)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
at android.widget.Toast$TN.handleShow(Toast.java:499)
at android.widget.Toast$TN.handleMessage(Toast.java:403)
at android.os.Handler.dispatchMessage(Handler.java:106)
at androidx.test.espresso.base.Interrogator.a(Interrogator.java:19)
at androidx.test.espresso.base.UiControllerImpl.a(UiControllerImpl.java:142)
at androidx.test.espresso.base.UiControllerImpl.a(UiControllerImpl.java:134)
at androidx.test.espresso.base.UiControllerImpl.a(UiControllerImpl.java:34)
at androidx.test.espresso.action.MotionEvents.a(MotionEvents.java:74)
at androidx.test.espresso.action.MotionEvents.a(MotionEvents.java:52)
at androidx.test.espresso.action.Tap.c(Tap.java:9)
at androidx.test.espresso.action.Tap.a(Tap.java:19)
at androidx.test.espresso.action.Tap.b(Tap.java:2)
at androidx.test.espresso.action.GeneralClickAction.perform(GeneralClickAction.java:22)
at androidx.test.espresso.ViewInteraction$SingleExecutionViewAction.perform(ViewInteraction.java:9)
at androidx.test.espresso.ViewInteraction.a(ViewInteraction.java:78)
at androidx.test.espresso.ViewInteraction.a(ViewInteraction.java:94)
at androidx.test.espresso.ViewInteraction.call(ViewInteraction.java:3)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
在 MainActivity OnCreate 中,我调用了这个膨胀 toast View 的方法:
private void initToastObjects() {
mToastCorrect = new Toast(this);
mToastWrong = new Toast(this);
// inflate view
LayoutInflater myInflater = LayoutInflater.from(this);
mLayoutCorrect = myInflater.inflate(R.layout.toast_correct, (ViewGroup) findViewById(R.id.toast_correct_container));
mLayoutWrong = myInflater.inflate(R.layout.toast_wrong, (ViewGroup) findViewById(R.id.toast_wrong_container));
}
我后来根据用户选择动态设置了不同的图像到吐司:
mToastCorrect.setView(mLayoutCorrect);
每次用户单击 correct/wrong 个答案时我都会显示 toast 消息,如果显示了另一个 toast,则取消:
// cancel previous wrong answer toast and display correct answer toast
try {
if (mToastWrong.getView().isShown()) {
mToastWrong.cancel();
}
mToastCorrect.show();
} catch (Exception e) {
e.printStackTrace();
}
感谢任何帮助!
- 我该如何解决这个问题?
- 为什么我只在 Android P 预览设备上收到此错误?
- 如果我在 MainActivity OnCreate 期间仅对 View 充气一次,为什么我会收到错误消息说视图 "has already been added to the window manager"?
经过几次尝试和错误,我设法修复了它。希望对遇到同样问题的其他人有所帮助。
显然,toast 消息处理已在 Android P (API 28) 中更改。在我的应用程序中,toast 消息是由单击按钮触发的,因此可以在上一个 toast 消息完成之前调用 toast 消息(请注意,两个 toast 消息是从同一个 Toast
对象调用的)。在 P (API 28) 之前的 Android 版本上,在前一个 toast 完成之前开始新的 toast 没有问题(即使它是相同的 Toast
对象)——新的toast 只是覆盖旧的 toast 并重新开始。
但是,在 Android P 中,相同的行为有时可能会抛出 IllegalStateException
.
我已经保留了对 Toast 对象的引用以重用它,所以我只需要取消它以防它被显示。由于取消它会导致 API 低于 28 的不良行为(例如吐司消息在很短的时间后消失),我插入了一个版本检查。这是解决方法代码:
// cancel previous toast and display correct answer toast
try {
if (mToastWrong.getView().isShown()) {
mToastWrong.cancel();
}
// cancel same toast only on Android P and above, to avoid IllegalStateException on addView
if (Build.VERSION.SDK_INT >= 28 && mToastCorrect.getView().isShown()) {
mToastCorrect.cancel();
}
mToastCorrect.show();
} catch (Exception e) {
e.printStackTrace();
}
我仍然不解的是为什么try-catch代码没有捕捉到异常(应用程序崩溃)。
我在 Pie 上看到了相同的崩溃报告,快速触发相同的自定义 Toast(由硬件音量按钮触发)。与 OP 的用例不同的是,我只有一个自定义 Toast 实例,只有它的自定义视图正在更新。
除了这次崩溃(我无法在 Pie 模拟器中重现自己,但在崩溃报告中看到),我还有另一个问题:在同一个 toast 上快速调用 Toast.show() 时(比如,20次),充其量只有前 2 个调用显示吐司然后它消失。在显示之前取消祝酒词没有帮助。
结论,烤面包片真的碎了...