EventBus用于消息传递,涉及到的知识点有观察者模式(发布订阅)、反射、注解、线程池、数据结构-队列等,这是都是面试过程中可能被问到的。
EventBus的使用,分三步:
1、注册
EventBus.getDefault().register(this);
this可以是任何类,一般是Activity、Fragment居多
2、订阅,要监听的消息类型和谁来接受消息,相当于观察者模式的回调
@Subscribe
public void aa(Object o) {}
必须添加注解,必须public,必须有且仅有一个参数
3、发送消息
EventBus.getDefault().post(obj);
这里,post的传参类型必须与接受消息的地方一致。
注册的过程是,通过反射的方式,获取所有方法,再过滤得到订阅方法。其中过滤条件如下: 1、判断修饰符,是共有方法,且不能是static、abstract; 2、有且仅有一个参数,这是EventBus内部判定条件; 3、有Subscribe注解,这是EventBus自定义的注解。 注册过程会将订阅者、要监听的消息、订阅方法(谁来处理)三者关联起来。
我自己写了一个简单的版本,便于理解。
public void register(Object o) {
Class clz = o.getClass();
/* 反射获取方法 */
Method[] methods = clz.getDeclaredMethods();
ArrayList<MsdInfo> msdInfos = new ArrayList<>();
for (Method _msd : methods) {
/* 判断修饰符 */
int modifiers = _msd.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && ((Modifier.STATIC | Modifier.ABSTRACT) & modifiers) == 0) {
/* 判断参数 */
Class[] paramsType = _msd.getParameterTypes();
if (paramsType.length == 1) {
/* 判断注解 */
Subscribe ann = _msd.getAnnotation(Subscribe.class);
if (ann != null) {
/* MsdInfo封装了订阅方法、消息 */
MsdInfo info = new MsdInfo();
info.msd = _msd;
info.paramType = paramsType[0];
msdInfos.add(info);
}
}
}
}
/* 关联订阅者和订阅方法、消息 */
map.put(o, msdInfos);
}
发布过程,根据消息找到订阅者,然后通过反射的方式执行订阅方法。下面是简单实现:
public void post(Object o) {
Set<Object> set = map.keySet();
for (Object _o : set) {
List<MsdInfo> msdInfos = map.get(_o);
for (MsdInfo _msd : msdInfos) {
if (o.getClass() == _msd.paramType) {
try {
_msd.msd.invoke(_o, o);
} catch (Exception e) {
}
}
}
}
}