【问题标题】:How to show a toast from a worker thread inside a service?如何从服务内的工作线程中显示祝酒词?
【发布时间】:2014-08-17 17:03:20
【问题描述】:

我正在使用 AlarmManager 来唤醒设备并运行一些任务。这些都是在 IntentService 中完成的,所以在一个与主线程分开的线程上。工作完成后,我想举杯敬酒。但是,我收到此日志警告,但没有显示 toast:

W/MessageQueue﹕ Handler (android.os.Handler) {b12716d0} sending message to a Handler on a dead thread
    java.lang.RuntimeException: Handler (android.os.Handler) {b12716d0} sending message to a Handler on a dead thread
            at android.os.MessageQueue.enqueueMessage(MessageQueue.java:320)
            at android.os.Handler.enqueueMessage(Handler.java:626)
            at android.os.Handler.sendMessageAtTime(Handler.java:595)
            at android.os.Handler.sendMessageDelayed(Handler.java:566)
            at android.os.Handler.post(Handler.java:326)
            at android.widget.Toast$TN.hide(Toast.java:370)
            at android.app.ITransientNotification$Stub.onTransact(ITransientNotification.java:55)
            at android.os.Binder.execTransact(Binder.java:404)
            at dalvik.system.NativeStart.run(Native Method)

我知道关于这个主题还有其他一些问题,但我已经尝试了所有建议,但都没有奏效。我正在使用:

Handler handler = new Handler();
handler.post(new Runnable()
{
    @Override
        public void run()
            {
                Toast.makeText(context, R.string.toast, Toast.LENGTH_LONG).show();
            }
});

我也试过了:

Handler handler = new Handler(Looper.getMainLooper());

我仍然收到警告,但没有吐司。

在我的 IntentService 中显示这个 toast 的方法是什么?

提前致谢!

【问题讨论】:

  • 使用Notification 而不是Toast。推理?一般来说,Services 不应该干扰 UI(除非您的应用程序中的关联 Activity 当前正在显示),而且 Toast 的生命周期非常短暂(仅几秒钟)。如果练习的目的是向用户传达一些有用的信息,那么用户很容易将视线从他们的设备上移开并完全错过Toast - 浪费您的时间和代码,并且没有用用户。 Notification 有更好的用途。
  • 是的,我在发布问题后不久就意识到了这一点,并相应地更改了我的应用程序。尽管如此,我认为这仍然是一个很好的话题,从学术上讲。感谢您的回答和cmets!

标签: android multithreading


【解决方案1】:

首先,您真的不应该从服务或任何不是由用户在很短时间内发起的任务发送 Toast 消息。否则用户将不知道 Toast 的来源;她甚至无法确定它来自哪个应用程序——这绝对是令人困惑和不好的做法。

但要回答您的问题,当您使用 new Handler() 创建一个处理程序时,它会附加到创建它的线程上。因此,如果您想从服务(从任何线程)向 UI/主线程发布内容,那么您应该在例如 onCreate() 方法中创建处理程序;因为onCreate(),通常是任何Android回调方法,都会在UI线程上调用。所以:

public class MyService extends Service {

    private Handler mMainThreadHandler;

    @Override
    public void onCreate() {
        mMainThreadHandler = new Handler();
    }

    [...]
}

或者,如果您想创建一个附加到 UI 线程的处理程序,并且不想关心它的创建位置,请使用new Handler(Looper.getMainLooper())。这样它就连接到主循环器上;这是主线程的looper。

public class MyService extends Service {

    private Handler mMainThreadHandler = new Handler(Looper.getMainLooper());

    [...]
}

我知道你写过你试过了;但它应该可以工作。

不过,我建议你不要打扰 Handlers;改用针。 Needle 是一个简单而强大的 Android 多线程库。有了它,你可以说:

Needle.onMainThread().execute(new Runnable() {
    @Override
    public void run() {
        // e.g. change one of the views
    }
});

在 GitHub 上查看:https://github.com/ZsoltSafrany/needle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-27
    • 2016-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多