自寫一個EventBus

首發於Enaium的我的博客java


EventBus,什麼是EventBus。git

EventBus是事件發佈-訂閱總線,簡單來講監聽一個事件,一個方法訂閱這個事件,若是事件調用,那麼訂閱了這個事件的方法也會跟着調用,這就是EventBus。github

建立一個註解,用於訂閱事件,名字能夠隨便起,固然也能夠叫Subscribe,我這裏叫Event。安全

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

建立Listener監聽器。測試

public class Listener {
}

建立MethodBean類,來儲存訂閱方法,Object是訂閱類的對象,Method就是被訂閱的方法。this

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

    public Method getMethod() {
        return method;
    }
}

建立一個EventManager,來管理訂閱的事件。線程

public class EventManager {
}

建立一個HashMap合集K是監聽器,V是被調用的方法,由於一個監聽器可能有多個方法,而且要保證線程安全,須要使用CopyOnWriteArrayList。code

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

建立register和unregister方法來註冊和取消註冊訂閱的對象。對象

public class EventManager {
    public void register(Object o) {

    }

    public void unregister(Object o) {
        
    }
}

註冊。blog

public void register(Object o) {
     Class<?> type = o.getClass();//獲取類。

    for (Method method : type.getDeclaredMethods()) {//遍歷出全部方法。
        if (method.getParameterTypes().length == 1 && method.isAnnotationPresent(Event.class)) {//保證方法只有一個參數,而且有Event這個註解。
            method.setAccessible(true);
            @SuppressWarnings("unchecked")
            Class<? extends Listener> listener = (Class<? extends Listener>) method.getParameterTypes()[0];

            MethodBean methodBean = new MethodBean(o, method);

            //把這些都put到events裏面。
            if (events.containsKey(listener)) {
                if (!events.get(listener).contains(methodBean)) {
                    events.get(listener).add(methodBean);
                }
            } else {
                events.put(listener, new CopyOnWriteArrayList<>(Collections.singletonList(methodBean)));
            }
        }
    }
}

取消註冊很簡單,只要將events的K和V移除就行。

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

建立一個getEvent方法來獲取一個監聽器的全部訂閱。

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

建立一個單例。

public enum Main {

    INSTANCE;

    EventManager eventManager = new EventManager();
    
}

回到剛纔建立的Listener類。

建立一個call方法來進行事件觸發操做,當事件觸發,獲取監聽器的全部訂閱方法來調用,參數就是當前的監聽器。

public class Listener {
    public void call() {
        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();
            }
        });
    }
}

建立一個監聽器。

public class UpdateEvent extends Listener {
}

一個簡單的EventBus已經寫好了,如今來測試一下。

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

源碼

相關文章
相關標籤/搜索