EventBus3.0是通过注解的方式来实现的,避免了以前版本不能混淆的缺陷,今天我就来实现一个简易版本的EventBus。
首先实现一个自定义的注解@Subscribe
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) //指定注解是针对方法的
@Retention(RetentionPolicy.RUNTIME) //指定注解生命周期存在于运行时
public @interface Subscribe {
boolean chosen() default true; //被注解,默认即为被标记
}
接着实现MyEventBus
的主体部分:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class MyEventBus {
private Map<Object, Method> methodMap; //存放对象和对象的方法
private List<Class<?>> parameterList; //存放methodMap里方法中的形参类型
private MyEventBus() {
methodMap = new ConcurrentHashMap<>();
parameterList = new ArrayList<>();
}
private static class MyEventBusLoader {
private static MyEventBus myEventBus = new MyEventBus();
}
//实现EventBus的getDefault()方法,本质上是单例模式
public static MyEventBus getDefault() {
return MyEventBusLoader.myEventBus;
}
/**
*
* @param o Example: 在Main.java中MyEventBus().getDefault().register(this);
*/
public void register(Object o) {
Class<?> c = o.getClass(); //获取类对象的Class
Method[] declaredMethods = c.getDeclaredMethods(); //通过反射获取传入的对象的所有方法
for (Method m : declaredMethods) {
//遍历所有方法,取出含有注解Subscribe的方法,并将该类对象及方法存入methodMap中,供post(Object)方法invoke调用
Subscribe annotation = m.getDeclaredAnnotation(Subscribe.class);
if (annotation != null && annotation.chosen()) {
methodMap.put(o, m);
//因为EventBus是通过方法的形参来判断该调用哪些方法,所以这里模仿获取被@Subscribe注解的方法的第一个参数作为判断标识
parameterList.add(m.getParameterTypes()[0]);
}
}
}
public void post(Object event) {
if (methodMap.isEmpty()) {
return;
}
//遍历methodMap,比较传入的参数event的类型和被注解的方法的形参类型是否相同,如果相同则通过反射调用对应的方法
for (Map.Entry<Object, Method> entry : methodMap.entrySet()) {
Object o = entry.getKey();
Method m = entry.getValue();
for (Class<?> c : parameterList) {
if (c.getTypeName().equals(event.getClass().getTypeName())) {
try {
m.invoke(o, event);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
}
这样就实现了一个简易的EventBus,只有一个时间总线的作用,不能够切换前后台线程,接下来测试。
首先定义一个测试类:
public class TestClass {
private MyEvent myEvent;
public TestClass() {
//向MyEventBus注册类
MyEventBus.getDefault().register(this);
}
@Subscribe
public void setMyEvent(MyEvent myEvent) {
this.myEvent = myEvent;
System.out.println("setMyEvent()被调用了");
}
}
接着在main方法中post
public class Main {
public static void main(String[] args) throws NoSuchMethodException {
new TestClass();
MyEventBus.getDefault().post(new MyEvent());
}
}
最后运行测试一下:
setMyEvent()被调用了
Process finished with exit code 0
可以看到程序已经成功运行了。