EventBus3.0源码解析——03. register 注册

register(注册)

//注册事件接收
EventBus.getDefault().register(this);
//注册事件总线,在获取到eventbus单例后就可以注册了
//注册方法中有两个至关重要的方法:
//1. 寻找到当前object对象中所有带@Subscribe注解标记的方法并保存起来
//2. 对当前object对象中所有带@Subscribe注解的方法进行订阅
public void register(Object subscriber) {
    //获得当前对象的class对象
	Class<?> subscriberClass = subscriber.getClass();
    //通过subscriberMethodFinder对象查找到当前class对象下的所有方法,并存入集合
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//1
    //程序锁
    synchronized (this) {
        //将当前对象下的所有方法遍历
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            //订阅(对象,方法)
            subscribe(subscriber, subscriberMethod);//2
        }
    }
}

findSubscriberMethods(Class)

//缓存当前class对象和对应的所有方法的并发map
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
//查找对象下的所有方法的源码
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    //这里是一个缓存,将当前class对象缓存起来
	List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
	//如果缓存中有,则直接使用缓存的数据
    if (subscriberMethods != null) {
	    return subscriberMethods;
	//是否忽略生成的索引
	if (ignoreGeneratedIndex) {
        //忽略,使用反射的方式查找subscriberMethods
	    subscriberMethods = findUsingReflection(subscriberClass);//1
	} else {
        //不忽略,使用信息的方式查找subscriberMethods
	    subscriberMethods = findUsingInfo(subscriberClass);//2
	}
    //如果当前缓存依然为努力了,则报错:当前传递进来的clas是对象没有附带@Subscribe注解对象
	if (subscriberMethods.isEmpty()) {
	    throw new EventBusException("Subscriber " + subscriberClass
	            + " and its super classes have no public methods with the @Subscribe annotation");
	} else {
        //存储缓存并返回查找的结果
	    METHOD_CACHE.put(subscriberClass, subscriberMethods);
	    return subscriberMethods;
	}
}

findUsingReflection(class)

通过反射的方式查找subscriberMethods

FindState

static class FindState {
    //当前eventbus中记录的所有订阅者方法
    final List<SubscriberMethod>subscriberMethods = new ArrayList<>();
    //将同一个class的方法存放在同一个class中
    final Map<Class, Object> anyMethodByEventType = new HashMap<>();
    //订阅者的方法key集合
    final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
    final StringBuilder methodKeyBuilder = new StringBuilder(128);
	//订阅者的class
    Class<?> subscriberClass;
    //当前传递进来的class
    Class<?> clazz;
    //是否跳过父类
    boolean skipSuperClasses;
    //订阅者信息
    SubscriberInfo subscriberInfo;
	
    //初始化
    void initForSubscriber(Class<?> subscriberClass) {
        //订阅class和当前class为同一个
        this.subscriberClass = clazz = subscriberClass;
        //默认不跳过父类
        skipSuperClasses = false;
        subscriberInfo = null;
    }
	//清除
    void recycle() {
        subscriberMethods.clear();
        anyMethodByEventType.clear();
        subscriberClassByMethodKey.clear();
        methodKeyBuilder.setLength(0);
        subscriberClass = null;
        clazz = null;
        skipSuperClasses = false;
        subscriberInfo = null;
    }
	//检查当前方法的事件类型
    boolean checkAdd(Method method, Class<?> eventType) {
        // 2级检查:只有事件类型的第一级(快速),如果需要,第二级有完整的签名。
        //这里判断当前订阅服务器是否已经监听了相同的方法参数了
        Object existing = anyMethodByEventType.put(eventType, method);
        //没监听,则返回true
        if (existing == null) {
            return true;
        } 
        //已经监听过了该方法,则判断上一个保存的existing是否是Method
        else {
            //如果existing对象是method类型,则订阅服务器则进行二次检查
            if (existing instanceof Method) {
                //如果eventtype保存的上一个value依然不是当前方法和参数,则抛出异常
                if (!checkAddWithMethodSignature((Method) existing, eventType)) {
                    // 抛出异常:非法状态
                    throw new IllegalStateException();
                }
                //官方解释:将任何非方法对象“消费”现有方法
                //这一步的目的暂不清楚,走到这一步,则会返回true
                anyMethodByEventType.put(eventType, this);
            }
            //
            return checkAddWithMethodSignature(method, eventType);
        }
    }
	//检查添加使用的方法签名:1,方法;2,参数的class对象
    //该方法目的是判断当前方法和参数是否已经被存储起来了
    //如果当前的key已经被某个class占用,则返回false
    //如果当前的key没有被占用,或者key存储的class与传递进来的方法的依附class相同,则返回true
    private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
        methodKeyBuilder.setLength(0);
        methodKeyBuilder.append(method.getName());//方法名
        methodKeyBuilder.append('>').append(eventType.getName());//参数名
		//生成一个方法key,key = 方法名>参数名
        String methodKey = methodKeyBuilder.toString();
        //当前方法的类class对象
        Class<?> methodClass = method.getDeclaringClass();
        //将当前class对象存储到对应的key之下
        Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
        //如果当前key没有被存储或者当前方法的类class对象是否是其父类
        //有可能是为了防止在找父类时覆盖了子类的方法,因为此方法是子类是重写,方法名参数名完全一样(方法签名);
        //另一个原因是可能是当一个类有多个方法监听同一个event(尽管一般不会这样做),也能将这些方法加进去。
        if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
            return true;
        } else {
            //如果当前的methodKey已经有值,则这里返回的methodClassOld是上一个存储的值
            //这里还原put,并且返回当前false,当前eventType参数已经保存过了
            subscriberClassByMethodKey.put(methodKey, methodClassOld);
            return false;
        }
    }
	//清除父类class
    void moveToSuperclass() {
        //如果清除父类class状态为true,则清空clazz
        if (skipSuperClasses) {
            clazz = null;
        } else {
            //获得当前clazz的父类class
            clazz = clazz.getSuperclass();
            //获得当前clazz的父类class的名字
            String clazzName = clazz.getName();
            //直接清除当前类的系统级父类,这会提高性能,所有java和javax或者android.开头的都直接清空
            if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
                clazz = null;
            }
        }
    }
}
//通过反射的方式查找subscriberMethods
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
    //FindState状态初始化
	FindState findState = prepareFindState();//1
    //寻找状态初始化订阅者
	findState.initForSubscriber(subscriberClass);
    //如果findState中的class对象不为null,则一直继续循环
	while (findState.clazz != null) {
        //使用反射的方式查找subscriberMethods
	    findUsingReflectionInSingleClass(findState);//3
        //移除父类class
	    findState.moveToSuperclass();
	}
    //这个方法非常重要,一个是获取methods,另一个是释放findState里面的map信息
	return getMethodsAndRelease(findState);//2
}

prepareFindState()

//真个EventBus中只存放4个FinsState对象
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
//初始化FindState
private FindState prepareFindState() {
    //同步锁,缓存当前class对象的并发map
    synchronized (FIND_STATE_POOL) {
        //循环出所有的FindState对象
        for (int i = 0; i < POOL_SIZE; i++) {
            FindState state = FIND_STATE_POOL[i];
            if (state != null) {
                //先将map中的对象置空,这里置空为的是防止并发造成的互相干扰
                FIND_STATE_POOL[i] = null;
                //返回已保存的FindState对象
                return state;
            }
        }
    }
    //map中没有对象则直接new一个FindState对象
    return new FindState();
}

getMethodsAndRelease(FindState)

//这个方法非常重要,一是获取methods,二是释放findState里面的map信息
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
    //将所有方法放入集合中
    List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
    //清空findstate中存储的信息,上一步已经将findstate中subscriberMethods放入了集合中,所以这里清空没有问题
    findState.recycle();//1
    //同步锁
    synchronized (FIND_STATE_POOL) {
        //这里的循环和之前的prepareFindState()方法相呼应
        //简单来说即使一个复用池,如果当前FindState的数组中有空位置则存入FinsState对象
        for (int i = 0; i < POOL_SIZE; i++) {
            //这里将findstate对象赋值,并发的时候这个复用池用的时候隔离,不用了回收
            if (FIND_STATE_POOL[i] == null) {
                FIND_STATE_POOL[i] = findState;
                break;
            }
        }
    }
    return subscriberMethods;
}

findUsingReflectionInSingleClass(FindState)

//使用反射的方式查找subscriberMethods
private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;//所有方法集合
    try {
        //这比getMethods更快,特别是当订阅者是像activity这样的臃肿类时
        //查找到所有不包含父类的public方法,有助于增加效率
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
        //如果报错这里再使用getMethods()
        methods = findState.clazz.getMethods();
        //跳过了父类方法
        findState.skipSuperClasses = true;
    }
    //循环所有方法
    for (Method method : methods) {
        //获得方法的修饰符
        int modifiers = method.getModifiers();
        //方法是public的且没有包含特定的修饰符
        //int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            //获得方法的所有参数
            Class<?>[] parameterTypes = method.getParameterTypes();
            //如果参数只有一个,订阅者只能写一个形参的方法
            if (parameterTypes.length == 1) {
                //获得@Subscribe注解,详见@Subscribe标签介绍
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                //如果有该注解则继续往下走
                if (subscribeAnnotation != null) {
                    //获得当前方法的参数
                    Class<?> eventType = parameterTypes[0];
                    //检查当前方法和参数,如果没有被添加到eventbus中,则往下走
                    if (findState.checkAdd(method, eventType)) {
                        //获得当前订阅者要求的线程类型
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        //subscriberMethods中新添加一个SubscriberMethod(方法,参数,线程类型,优先级,是否分发粘性事件)
                        findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                    }
                }
            }
            //如果strictMethodVerification = true且当前方法有@Subscribe注解且参数不为1个,则抛出异常
            else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                //抛出异常:订阅者方法有且只有一个参数
                throw new EventBusException("@Subscribe method " + methodName +
                        "must have exactly 1 parameter but has " + parameterTypes.length);
            }
        }
        //如果strictMethodVerification = true;且当前方法带有注解@Subscribe则这里抛出异常
        else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
            String methodName = method.getDeclaringClass().getName() + "." + method.getName();
            //抛出异常:非法的@Subscribe方法:必须是公共的、非静态的和非抽象的方法
            throw new EventBusException(methodName +
                    " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
        }
    }
}

findUsingInfo(class)

使用方法信息查找subscriberMethods

//用于由注释处理创建的生成索引类的基类
public interface SubscriberInfo {
    Class<?> getSubscriberClass();

    SubscriberMethod[] getSubscriberMethods();

    SubscriberInfo getSuperSubscriberInfo();

    boolean shouldCheckSuperclass();
}
//订阅者信息索引
//subscriberInfoIndexes是该对象的一个有序集合arraylist
public interface SubscriberInfoIndex {
    SubscriberInfo getSubscriberInfo(Class<?> subscriberClass);
}
//使用方法信息查找subscriberMethods
//EventBus 3.0刚加的功能,特点是比反射快
//在编译期完成subscriber的注册register,而不是在注册期间
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    //初始化
	FindState findState = prepareFindState();
	findState.initForSubscriber(subscriberClass);
	while (findState.clazz != null) {
        //获得订阅者的信息
	    findState.subscriberInfo = getSubscriberInfo(findState);//1
	    if (findState.subscriberInfo != null) {
            //获得订阅者订阅的所有方法,这一步很关键,如果没有存储某些方法,需要存储到subscriberMethods中
            //获得当前订阅者信息里存储的所有订阅者方法
	        SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
	        for (SubscriberMethod subscriberMethod : array) {
                //依然检查当前eventbus是否存储了该方法和参数
	            if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                    //没有存储则存储到subscriberMethods中
	                findState.subscriberMethods.add(subscriberMethod);
	            }
	        }
	    } else {
            //如果没有获取到订阅者信息,则依然使用反射的方法去获得findState
	        findUsingReflectionInSingleClass(findState);
	    }
        //清除当前类的父类
	    findState.moveToSuperclass();
	}
    //返回所有当前类记录的需要订阅的方法并且清除Findstatus对象
	return getMethodsAndRelease(findState);
}

getSubscriberInfo(FindState)

//获得订阅者的信息
private SubscriberInfo getSubscriberInfo(FindState findState) {
    //如果订阅者信息不为null并且订阅者的父类的信息也不为null
    if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
        //将订阅者父类信息赋值给订阅者
        SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
        //如果clazz和订阅者class一致,则返回订阅者信息
        if (findState.clazz == superclassInfo.getSubscriberClass()) {
            return superclassInfo;
        }
    }
    //如果有订阅者信息索引则直接从索引中拿出来
    if (subscriberInfoIndexes != null) {
        for (SubscriberInfoIndex index : subscriberInfoIndexes) {
            //从索引中获取当前findstate的class对象所存储的订阅者信息
            SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
            if (info != null) {
                return info;
            }
        }
    }
    return null;
}

这里有一个延申,订阅者信息索引的保存方法,EventBusBuilder中的addIndex(SubscriberInfoIndex)

注:源码中addIndex这个方法并没有用到,暂不清楚订阅者信息索引如何起作用的

subscribe(Object,SubscriberMethod)

当执行register的时候,会将当前注册的对象中的所有带有@Subscribe注解标记的方法都收集起来,上面这部分详细的分析整个收集过程

//将当前class对象中已经标记了的订阅存起来
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
//订阅
//参数:
//1. 订阅的object
//2. 当前object中被@Subscribe标记的某个方法
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
	//获得当前方法的参数的class对象,订阅的方法有且只有一个参数
	Class<?> eventType = subscriberMethod.eventType;
	//new一个Subscription,传入object和subscriberMethod
	Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//1
    //查询当前是否已经保存了订阅对象的Subscription集合
    //CopyOnWriteArrayList并发安全且性能比Vector好
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    //如果当前订阅对象的Subscription不存在则new一个并发安全的集合
	if (subscriptions == null) {
	    subscriptions = new CopyOnWriteArrayList<>();
        //保存起来
	    subscriptionsByEventType.put(eventType, subscriptions);
	} else {
        //如果已经保存了,则判断当前集合中是否已经包含了newSubscription对象
	    if (subscriptions.contains(newSubscription)) {
            //如果包含了,则抛出异常:订阅者已经被标记过了
	        throw new EventBusException("Subscriber " + subscriber.getClass()
                                        + " already registered to event " + eventType);
	    }
	}
	//当前循环是将订阅的优先级实现,优先级高的排序在集合的最上面
	int size = subscriptions.size();
	for (int i = 0; i <= size; i++) {
	    if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
	        subscriptions.add(i, newSubscription);
	        break;
	    }
	}
	//查询当前object中的订阅者有多少个
	List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    //如果当前object没有记录订阅者则new一个并且保存起来
	if (subscribedEvents == null) {
	    subscribedEvents = new ArrayList<>();
	    typesBySubscriber.put(subscriber, subscribedEvents);
	}
    //添加订阅的class对象
	subscribedEvents.add(eventType);
	//粘性事件
	if (subscriberMethod.sticky) {
        //事件继承???
	    if (eventInheritance) {
            //官方解释:
            //现有的事件的事件类型的子类必须被考虑。
            //注意:遍历所有事件可能与很多棘手的事件,效率低下,
            //因此数据结构应该改为允许更有效的查找,
            //额外的map存储子类的超类:class > List<class>;
	        Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
	        for (Map.Entry<Class<?>, Object> entry : entries) {
                //候选人事件类型;
	            Class<?> candidateEventType = entry.getKey();
                //当前方法的类class对象是否是其父类
	            if (eventType.isAssignableFrom(candidateEventType)) {
                    //如果当前类是粘性事件的父类,则检查粘贴事件是否已订阅
	                Object stickyEvent = entry.getValue();
	                checkPostStickyEventToSubscription(newSubscription, stickyEvent);//2
	            }
	        }
	    } else {
            //直接检查粘性事件是否已经post到订阅中去了
	        Object stickyEvent = stickyEvents.get(eventType);
	        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
	    }
	}
}

Subscription

//订阅
final class Subscription {
    //订阅者
    final Object subscriber;
    //所订阅的方法
    final SubscriberMethod subscriberMethod;
    //调用{@link EventBus#invokeSubscriber(PendingPost)}来防止竞争条件
    //队列事件交付{@link EventBus#invokeSubscriber(PendingPost)}检查该对象是否为false。
    volatile boolean active;//是否是有效的

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Subscription) {
        	//如果对比对象属于Subscription
            Subscription otherSubscription = (Subscription) other;
            //订阅的object对象相同且订阅的方法相同,则返回true
            return subscriber == otherSubscription.subscriber
                    && subscriberMethod.equals(otherSubscription.subscriberMethod);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        //object的hashcode+方法的hashcode
        return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
    }
}

SubscriberMethod

//内部使用的EventBus和生成的订阅者索引
public class SubscriberMethod {
    final Method method;//订阅的方法
    final ThreadMode threadMode;//订阅发送到线程的模式
    final Class<?> eventType;//订阅的方法参数的class
    final int priority;//发送优先级
    final boolean sticky;//粘性事件
    //用于高效比较
    String methodString;
	
    public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
        this.method = method;
        this.threadMode = threadMode;
        this.eventType = eventType;
        this.priority = priority;
        this.sticky = sticky;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        } else if (other instanceof SubscriberMethod) {
            //检查方法名
            checkMethodString();
            SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
            otherSubscriberMethod.checkMethodString();
            //两个方法名作对比
            return methodString.equals(otherSubscriberMethod.methodString);
        } else {
            return false;
        }
    }
	//检查方法名
    private synchronized void checkMethodString() {
        if (methodString == null) {
            //tostring有更多的开销,只取方法的相关部分
            StringBuilder builder = new StringBuilder(64);
            //该方法属于哪个class
            builder.append(method.getDeclaringClass().getName());
            //方法名
            builder.append('#').append(method.getName());
            //参数名
            builder.append('(').append(eventType.getName());
            methodString = builder.toString();
        }
    }

    @Override
    public int hashCode() {
        return method.hashCode();
    }
}

checkPostStickyEventToSubscription(Subscription,Object)

//检查粘性事件是否post到了订阅者中
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
    if (stickyEvent != null) {
        //官方解释
        //如果订阅者试图中止事件,它将失败(事件在发布状态下没有被跟踪)
        //很奇怪的箱子,我们这里不处理。
        //这里详见post源码解析
        postToSubscription(newSubscription, stickyEvent, isMainThread());
    }
}

总结

  1. 注册的方法是register(Object subscriber)
    1. 这里的subscriber对象大多数为Activity、Fragment或者Class。它们其中包含了多个带有@Subscribe注解的方法,用来接收eventbus发送的消息
  2. List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
  3. 这个方法的意思是旨在找出当前subscriber对象下所有的标记了@Subscribe的方法并且生成相对应的SubscriberMethod对象
  4. findSubscriberMethods(subscriberClass)方法的延伸解析可以从上述代码中得知,它就是将当前subscriber对象中的所有标记了@Subscribe的Method缓存起来,有缓存则返回,没缓存则先缓存再返回SubscriberMethod集合。
  5. subscribe(subscriber, subscriberMethod);
    1. 将所有SubscriberMethod对象进行循环订阅
    2. 这个循环意在将每个SubscriberMethod对象与之对应的subscriber对象绑定在一起并缓存起来。
    3. 绑定好以后则代表当前subscriber对象中的所有method都已绑定,subsriber对象的注册则完成
    4. 当eventbus发动post的时候,所有缓存起来的method方法都会寻找与之对应的post出去的object对象是否吻合,如果吻合则invoke到该method中。具体post再后面会讲到
发布了113 篇原创文章 · 获赞 48 · 访问量 34万+

猜你喜欢

转载自blog.csdn.net/yehui928186846/article/details/99305983
今日推荐