使用Guava的EventBus,可以在创建总线的线程上运行用户代码吗?

时间:2013-12-24 01:26:33

标签: java android multithreading guava

使用Guava的EventBus,我希望能够从后台线程(称为“后台”)发布到更新UI的特定线程(在本例中为线程“main”)。我认为以下内容可行,但这会调用后台线程中的订阅者代码:

package com.example;

import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.MoreExecutors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EventBusTester {

    private static final Logger log = LoggerFactory.getLogger(EventBusTester.class);

    public static void main(String... args) {
        new EventBusTester().run();
    }

    private void run() {
        log.info("Starting on thread {}.", Thread.currentThread().getName());

        final EventBus eventBus = new AsyncEventBus(MoreExecutors.sameThreadExecutor());
        eventBus.register(this);

        Thread background = new Thread(new Runnable() {
            @Override
            public void run() {
                long now = System.currentTimeMillis();
                eventBus.post(now);
                log.info("Posted {} to UI on thread {}.", now, Thread.currentThread().getName());
            }
        }, "background");
        background.start();
    }

    @Subscribe
    public void updateUi(Long timestamp) {
        log.info("Received {} on UI on thread {}.", timestamp, Thread.currentThread().getName());
    }
}

这将打印以下内容:

02:20:43.519 [main] INFO  com.example.EventBusTester - Starting on thread main.
02:20:43.680 [background] INFO  com.example.EventBusTester - Received 1387848043678 on UI on thread background.
02:20:43.680 [background] INFO  com.example.EventBusTester - Posted 1387848043678 to UI on thread background.

所以我的问题是:

  1. 是否有可能做我想做的事,例如使用ExecutorService我不知何故错过了,或编写自定义ExecutorService,或
  2. 我需要一些其他库才能完成此任务吗?例如。 Square的Otto(因为我也会在Android上使用它)。
  3. 我宁愿和纯净的番石榴呆在一起。

    谢谢!

2 个答案:

答案 0 :(得分:5)

如果使用EventBus实例,则@Subscribe方法将在发布事件的同一线程上执行。

如果您想要做一些不同的事情,请使用AsyncEventBus,您可以提供Executor来定义事件发布时的确切行为。

例如,在Android上,要使每个@Subscribe方法在主线程上运行,您可以执行以下操作:

EventBus eventBus = new AsyncEventBus(new Executor() {

    private Handler mHandler;

    @Override
    public void execute(Runnable command) {
        if (mHandler == null) {
            mHandler = new Handler(Looper.getMainLooper());
        }
        mHandler.post(command);
    }
});

Looper.getMainLooper()返回应用程序的主looper,它位于应用程序的主线程上。

答案 1 :(得分:3)

  1. 在UI应用程序中,有一个运行事件调度循环的线程。它正在处理用户输入事件和调用处理程序。通常,UI框架提供了一些在此线程中执行代码的方法,如SwingUtilities.invokeLater(Runnable)
  2. AsyncEventBus允许您传递传递Executor,它将为此调用特定于UI框架的函数。
  3. 这里有一些与从android上的工作线程执行UI代码相关的问题。