Toast的IllegalStateException在Android P上预览

时间:2018-08-21 21:32:19

标签: android illegalstateexception android-inflate android-toast

在尝试发布我的应用进行生产时,发布前的报告通知我有关Pixel 2 Android P Preview设备的错误。该错误与我收到的自定义祝酒消息有关,该消息说“视图已被添加到窗口管理器中”:

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$1.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$1.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$1.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视图:

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

每次用户单击正确/错误答案时,我都会显示土司消息,如果显示其他土司,则将其取消:

    // cancel previous wrong answer toast and display correct answer toast
    try {
        if (mToastWrong.getView().isShown()) {
            mToastWrong.cancel();
        }
        mToastCorrect.show();
    } catch (Exception e) {
        e.printStackTrace();
    }

感谢您的帮助!

  1. 我应该如何解决此问题?
  2. 为什么仅在Android P Preview设备上会出现此错误?
  3. 如果在MainActivity OnCreate期间仅对View进行一次充气,为什么我会收到一条错误消息,指出视图“已被添加到窗口管理器中”?

2 个答案:

答案 0 :(得分:2)

经过几次试验和错误,我设法修复了它。希望对其他遇到相同问题的人有所帮助。

显然,Android P(API 28)中更改了吐司消息处理。在我的应用中,单击按钮即可触发Toast消息,因此可以在完成上一个Toast消息之前调用Toast消息(请注意,这两个Toast消息是从同一Toast对象调用的)。在P(API 28)之前的Android版本上,在完成之前的新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代码没有捕获异常(应用程序崩溃)。

答案 1 :(得分:0)

我在Pie上看到了相同的崩溃报告,并快速触发了相同的自定义Toast(由硬件音量按钮触发)。与OP用例的不同之处在于,我只有一个自定义Toast实例,并且只有其自定义View被更新。

除了这次崩溃(我无法在Pie仿真器中进行自我测试,而是在崩溃报告中看到)之外,我还有另一个问题:在同一个Toast上快速调用Toast.show()时(比如说20次),充其量,前两个呼叫会显示吐司,然后消失。在显示吐司之前先取消吐司无济于事。

结论,吐司真的在P上坏了...