With Guava’s EventBus, can I run subscriber code on the thread that created the bus?
With 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 think the following would work, but this would call the subscriber code from a 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 will print 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 question is:
- Is it possible to do what I want, such as using an ExecutorService that I somehow missed, or writing a custom ExecutorService, or
- Do I need some other libraries to do this? For example. Square’s Otto (because I’ll use it on Android too).
I’d rather stay at pure Guava, though.
Thank you!
Solution
EventBus
If you use an instance, the method executes on the same thread that publishes the @Subscribe
event.
If you want to do something different, use AsyncEventBus
, where you can provide a Executor
to define the exact behavior when the event is published.
For example, on Android, to have each @Subscribe
method run on the main thread, you can do the following:
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()
Returns the main looper for the application, which is on the application’s main thread.