Search code examples
javaandroidmultithreadingguava

Using Guava's EventBus, possible to run subscriber code on thread that created the bus?


Using Guava's EventBus, I want to be able to post from a background thread (called "background") to a specific thread (in this case, thread "main") that updates the UI. I thought the following would work, but this calls the subscriber code from the background thread:

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

This prints the following:

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.

So my questions are:

  1. Is it possible to do what I want, e.g. with an ExecutorService I've somehow missed, or writing a custom ExecutorService, or
  2. Do I need some other library to accomplish this? E.g. Square's Otto (because I'll be using this on Android as well).

I'd rather stay with pure Guava, though.

Thanks!


Solution

    1. In UI applications, there is a thread running an event dispatch loop. which is processing user input events and calling handlers. Typically, UI framework provides some way to execute your code in this thread, like SwingUtilities.invokeLater(Runnable)
    2. AsyncEventBus allows you to pass pass Executor, which will be calling UI-framework specific function for that.
    3. There are a few questions here related to executing UI code from a worker thread on android.