为什么在Android中,如果上下文相同,Toast的制作地点很重要?

10

我有一个旧版的IntentService,它尝试使用Toast消息来显示错误消息。1 我希望这些消息能够被显示出来,并且已经添加了代码来将它们显示在正确的线程上。最简单的更改是传递构建好的Toast对象,然后在UI线程上显示它。然而,只有在发布的runnable中创建Toast,才能让Toast显示出来,如果我传递一个预先制作好的Toast对象,则不能正常工作。

这个可以运行:

@Override
protected void onHandleIntent(Intent intent) {
    showToast("Error", Toast.LENGTH_LONG);
}

private void showToast(final String msg, final int duration) {
    new Handler(getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            // Make and show the toast in the posted runnable
            Toast.makeText(getApplicationContext(), msg, duration).show();
        }
    });
}

不起作用

@Override
protected void onHandleIntent(Intent intent) {
    // Make the toast here
    Toast myToast = Toast.makeText(getApplicationContext(), "Error", Toast.LENGTH_LONG);
    showToast(myToast);
}

private void showToast(final Toast toast) {
    new Handler(getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            // Show the toast here
            toast.show();
        }
    });
}

在这两种情况下,上下文都是应用程序上下文,在源代码中我没有看到任何会导致其中一个版本工作而另一个版本不工作的东西。相反,后者与如果Toast直接在IntentService中显示时具有相同的问题:“Handler(android.os.Handler){...}向死线程上的处理程序发送消息”,Toast不消失等。

为什么Toast必须在主线程上创建而不仅仅是在那里显示

1. 旧版 = 我认为在Toast中显示错误消息并不是很好的用户界面,而且我认为服务直接向用户显示消息也不是个好主意,但这就是我手头的代码,我想让它变得更好一点。

1个回答

10
在您发布的第二段代码中,Toast在后台线程中创建,该线程具有looper和handler设置(这是IntentService的目的)。
Toast使用当前线程的looper来创建handler,但一旦IntentService完成onHandleIntent中的工作并停止自身(如果没有其他意图需要处理),则会销毁您的Toast处理程序依赖的线程。
327行:https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/widget/Toast.java 在可运行的代码中创建Toast有效,因为此时当前线程是UI线程。

看起来那确实是问题的根源。我想知道为什么他们要在那里创建处理程序,而不是更靠近需要它的地方。对于此时此刻非常简单的对象来说,似乎是不必要的复杂化。 - blahdiblah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接