EventBus作为常用框架之一,从早期的EventBus2.0到目前3.+,经历了从反射到apt实现的转变,本文以原理分析为主,以反射方式实现早期的2.0框架。
EventBus的核心在于:将被注解的方法(如@Subscribe注解方法),放到Map中。后续post的时候,根据post的参数类型(如Message类)在Map中找到对应的方法,并调用。
将步骤分解后,就是以下两个主要操作:
1、注册:通过特定的注解(如@Subscribe),将被注解的方法,添加到Map中。
2、信息传递:通过post方法,在Map中查找符合要求的方法,并反射调用。
根据分析,我们再将以上的步骤细化,如下:
1、定义一个注解Subscribe,用于标识哪些方法需要被添加到Map中。
//运行时起效
@Retention(RetentionPolicy.RUNTIME)
//针对方法起效
@Target(ElementType.METHOD)
public @interface Subscribe {
ThreadModel threadModel() default ThreadModel.ANY;
}
其他相关定义:
//线程控制枚举:任意,主线程,子线程
public enum ThreadModel {
ANY,
MAIN,
BACKGROUND
}
2、定义一个单例类(ABus),Map将作为变量放置在该类中,用于存储被Subscribe标记的方法。其中Map的key设为Object类型,可为页面或其他类对象。
//定义一个单例类,也就是通讯总线Bus
public class ABus {
//用于存储某个类上,有被subscribe标识的方法
private Map
3、在ABus中,定义register(Object object)方法,入参object可为Activity、Fragment或者其他类对象。后续将根据这个object查找该类上所有有Subscribe标识的方法,并存入到Map中。
//注册类,将会把该类下的subscribe标识的方法,放入到Map中
public void register(Object object) {
if (object == null) {
return;
}
List methodLs = methods.get(object);
if (methodLs == null) {
this.methods.put(object, findSubscriber(object));
}
}
...
//查找类下,所有被subscribe标识的方法
private List findSubscriber(Object object) {
List methods = new ArrayList<>();
Class> aClass = object.getClass();
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
//判断该方法是否含有Subscribe注解标识
Subscribe subscribe = declaredMethod.getAnnotation(Subscribe.class);
if (subscribe == null) {
continue;
}
//参数获取
Class>[] parameterTypes = declaredMethod.getParameterTypes();
//特殊要求:参数只能是一个,不能为空,也不能超过一个
if (parameterTypes.length != 1) {
continue;
}
methods.add(declaredMethod);
}
return methods;
}
4、在ABus中,定义post方法post(final Object msg)。post方法将遍历Map中的方法,匹配到与post入参一致的类,并根据线程要求,分发信息。
//post方法
public void post(final Object msg) {
//获取Map中的所有key
Set
5、最后,在ABus中,补全unRegister方法,避免内存泄漏,完成整个的设计。
public void unRegister(Object object) {
if (object == null) {
return;
}
if(methods != null){
methods.remove(object);
}
}
这里写的ABus与EventBus原理类似,功能一致。百多行代码即实现了整体的通讯总线。