First published on Enaium’s personal blog


EventBus. What is EventBus?

EventBus is an event publish-subscribe bus. In short, it listens for an event, a method subscribes to the event, and if the event is called, the method subscribing to the event is called as well.

Create an annotation to Subscribe to an Event. You can call it Subscribe, or you can call it Event.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Event {
}
Copy the code

Create a Listener.

public class Listener {}Copy the code

Create a MethodBean class to store the subscribed methods, with Object being the subscribed class Object and Method being the subscribed Method.

public class MethodBean {
    private final Object object;
    private final Method method;

    public MethodBean(Object object, Method method) {
        this.object = object;
        this.method = method;
    }

    public Object getObject(a) {
        return object;
    }

    public Method getMethod(a) {
        returnmethod; }}Copy the code

Create an EventManager to manage subscribed events.

public class EventManager {}Copy the code

Create a HashMap collection where K is the listener and V is the method to be called, because a listener can have multiple methods, and to be thread-safe, use CopyOnWriteArrayList.

public class EventManager {
    private final HashMap<Class<? extends Listener>, CopyOnWriteArrayList<MethodBean>> events = new HashMap<>();
}
Copy the code

Create register and unregister methods to register and unregister subscribed objects.

public class EventManager {
    public void register(Object o) {}public void unregister(Object o) {}}Copy the code

Registration.

public void register(Object o) { Class<? > type = o.getClass();// Get the class.

    for (Method method : type.getDeclaredMethods()) {// Iterate through all the methods.
        if (method.getParameterTypes().length == 1 && method.isAnnotationPresent(Event.class)) {// Ensure that the method takes only one argument and has an Event annotation.
            method.setAccessible(true);
            @SuppressWarnings("unchecked")
            Class<? extends Listener> listener = (Class<? extends Listener>) method.getParameterTypes()[0];

            MethodBean methodBean = new MethodBean(o, method);

            // put all these into events.
            if (events.containsKey(listener)) {
                if (!events.get(listener).contains(methodBean)) {
                    events.get(listener).add(methodBean);
                }
            } else {
                events.put(listener, newCopyOnWriteArrayList<>(Collections.singletonList(methodBean))); }}}}Copy the code

Unregistering events is as simple as removing the K and V from events.

public void unregister(Object o) {
    events.values().forEach(methodBeans -> methodBeans.removeIf(methodMethodBean -> methodMethodBean.getObject().equals(o)));
    events.entrySet().removeIf(event -> event.getValue().isEmpty());
}
Copy the code

Create a getEvent method to get all the subscriptions for a listener.

public CopyOnWriteArrayList<MethodBean> getEvent(Class<? extends Listener> type) {
    return events.get(type);
}
Copy the code

Create a singleton.

public enum Main {

    INSTANCE;

    EventManager eventManager = new EventManager();
    
}
Copy the code

Go back to the Listener class you just created.

Create a call method to trigger the event. When the event is triggered, all the subscribed methods of the listener are called with the current listener argument.

public class Listener {
    public void call(a) {
        CopyOnWriteArrayList<MethodBean> methodBeans = Main.INSTANCE.eventManager.getEvent(this.getClass());

        if(methodBeans == null) {
            return;
        }

        methodBeans.forEach(event -> {
            try {
                event.getMethod().invoke(event.getObject(), this);
            } catch(IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); }}); }}Copy the code

Create a listener.

public class UpdateEvent extends Listener {}Copy the code

Now that a simple EventBus has been written, let’s test it out.

public enum Main {

    INSTANCE;

    EventManager eventManager = new EventManager();

    public static void main(String[] args) {
        Main.INSTANCE.eventManager.register(new Test());//register
        new UpdateEvent().call();
    }

    static class Test {
        @Event
        public void on(UpdateEvent e) {
            System.out.println("Event trigger"); }}}Copy the code

The source code