EventBus -1,订阅、发布过程

95 阅读1分钟

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) {
                }
            }
        }
    }
}