Witness, a Simple Android and Java Event Emitter
Witness, a simple Android and Java Event Emitter
Source. I found this in an image search for ‘witness’. Had to use it. =)
I’ve been working on a project for Google Glass and Android that requires asynchronous messages to be passed around between threads. In the past, I’ve used Square’s Otto for this, but I wasn’t thrilled with the performance. Additionally, Otto makes some assumptions about which thread to run on, and how many threads to run with, that I wasn’t crazy about. Before continuing, I should point out that Otto is configurable, and some of these basic assumptions can be dealt with in the configs. Regardless, I felt like writing my own.
Code
Witness is a really simple event emitter for Java. The idea here is to build a really simple structure that can be used to implement observers easily. It’s sort of like JavaScript’s Event Emitter, and the code is short enough to read in its entirety.
I’ll start with Reporter
because it’s so simple. Essentially, this is just an interface that you implement if you want your class to be able to receive events.
The Witness
class maps class types to Reporter
instances. This means that for a given data type, Witness
will fan out the event to all registered Reporter
s. It uses an ExecutorService
with a pool size of 10 threads to accomplish this as quickly as possible off of the main thread:
Usage
To receive events for a specific datatype, the receiving class needs to implement the Reporter
interface, then register for whatever data types the following way:
Witness.register(EventTypeOne.class, this);
Witness.register(EventTypeTwo.class, this);
When you’re done listening, unregister with the following:
Witness.remove(EventTypeOne.class, this);
Witness.remove(EventTypeTwo.class, this);
To publish events to listeners:
Witness.notify(event);
Handling events in the Reporter
:
@Override
public void notifyEvent(Object o) {
if (o instanceof SomeObject) {
objectHandlingMethod(((SomeObject) o));
}
}
Android, it is a good idea to use a handler, to force the event handling to run on the thread you expect. E.g., if you need code run on the main thread, in an Activity or Service:
public class MyActivity extends Activity implements Reporter {
private Handler handler = new Handler();
// ...
@Override
public void notifyEvent(final Object o) {
handler.post(new Runnable() {
@Override
public void run() {
if (o instanceof SomeObject) {
objectHandlingMethod(((SomeObject) o));
}
}
});
}
}
Notes
Events are published on a background thread, using an ExecutorService
, backed by a BlockingQueue
.
This has a few important implications:
- Thread safety
- You need to be careful about making sure that whatever you’re using this for is thread safe
- UI/Main thread
- All events will be posted to background threads
- Out of order
- Events are handled in parallel, so it is possible for them to come in out of order
Please find this project on GitHub. If I get enough questions about it, I might be willing to take the time to package it and submit it to maven central.
Update
+Dietrich Schulten had the following comment:
It has the effect that events can be delivered on arbitrary threads. The event handler must be threadsafe, must synchronize access to shared or stateful resources, and be careful not to create deadlocks. Otoh if you use a single event queue, you avoid this kind of complexity in the first place. I’d opt for the latter, threadsafe programming is something you want to avoid if you can.
I should note that my usage is all on Android, where I’m explicitly specifying the thread that the events will run on using Handler
s. I haven’t used this in a non-Android environment, and I’m not entirely sure how to implement the equivalent behavior for regular Java.