EventBus 源码解析(一)

EventBus 看见N次了,刚换工作,然后在这边项目里面又到处看到。好吧,既然如此多的人在使用,那么我也来看看,不然真的变out man了。

其实初始EventBus,发现使用很简单,通过EventBus.getDefault()获取单列对象,然后register(object),要调用函数时post(data),最后不使用的时候unregister(object)。既然这么使用那么我们根据这个流程来看EventBus。

首先,看EventBus的构造函数。看到EventBusBuilder,就想起建造者模式,果然EventBusBuilder有build()方法来构建EventBus。Builder 对于建造者模式来说差不多属性的配置,然后再量产对象出来。当然那些参数在代码里面会分析,主要是eventInheritance的使用。

public EventBus() {
    this(DEFAULT_BUILDER);
}

EventBus(EventBusBuilder builder) {
    ...
}
接着,来看register()。其实很多个register最终都调用register(Object subscriber, boolean sticky, int priority),下面代码。注册这里先找我们这个对象里面需要可以发送消息的函数,并且把他们缓存起来,

private synchronized void register(Object subscriber, boolean sticky, int priority) {
 // subscriber是我们注册的对象,sticky接下来会分析到,priority优先级
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
    for (SubscriberMethod subscriberMethod : subscriberMethods) {
        subscribe(subscriber, subscriberMethod, sticky, priority);
    }
}
下面我们来看findSubscriberMethods()函数,

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
	String key = subscriberClass.getName();
	List<SubscriberMethod> subscriberMethods;
	synchronized (methodCache) { //这里首先看有没有缓存,对于可能多线程操作,加上<span style="font-family: Arial, Helvetica, sans-serif;">synchronized,</span>超严谨;这里我以后也要注意了
		subscriberMethods = methodCache.get(key);
	}
	if (subscriberMethods != null) { //有则返回缓存
		return subscriberMethods;
	}
	subscriberMethods = new ArrayList<SubscriberMethod>();
	Class<?> clazz = subscriberClass;
	HashSet<String> eventTypesFound = new HashSet<String>();
	StringBuilder methodKeyBuilder = new StringBuilder();
	while (clazz != null) {
		String name = clazz.getName();
		if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
			// Skip system classes, this just degrades performance
			break;
		}

		// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
		Method[] methods = clazz.getDeclaredMethods(); //
		for (Method method : methods) {
			String methodName = method.getName();
			if (methodName.startsWith(ON_EVENT_METHOD_NAME)) { // 以onEvent开头的函数
				int modifiers = method.getModifiers();
				if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
<span style="white-space:pre">					</span>//需public,并且排除abstract、static、bridge、synthetic四种类型的
					Class<?>[] parameterTypes = method.getParameterTypes();
					if (parameterTypes.length == 1) { //这里参数只能一个
						String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
						ThreadMode threadMode;
						if (modifierString.length() == 0) { // 这里就是"onEvent"的处理
							threadMode = ThreadMode.PostThread;
						} else if (modifierString.equals("MainThread")) { //"onEventMainThread"的处理
							threadMode = ThreadMode.MainThread;
						} else if (modifierString.equals("BackgroundThread")) { //"onEventBackgroundThread"<span style="font-family: Arial, Helvetica, sans-serif;">的处理</span>
							threadMode = ThreadMode.BackgroundThread;
						} else if (modifierString.equals("Async")) { // "onEventAsync"的处理
							threadMode = ThreadMode.Async;
						} else {
							if (skipMethodVerificationForClasses.containsKey(clazz)) { //除非你将这个class添加入skip的class
								continue;
							} else { // 否则你这样命名会抛异常
								throw new EventBusException("Illegal onEvent method, check for typos: " + method);
							}
						}
						Class<?> eventType = parameterTypes[0];
						methodKeyBuilder.setLength(0);
						methodKeyBuilder.append(methodName);
						methodKeyBuilder.append('>').append(eventType.getName());
						String methodKey = methodKeyBuilder.toString();
						if (eventTypesFound.add(methodKey)) { 
							// Only add if not already found in a sub class
							subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
						}
					}
				} else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
					Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."
							+ methodName);
				}
			}
		}
		clazz = clazz.getSuperclass(); // 去查找父类
	}
	if (subscriberMethods.isEmpty()) { // 如果没有找到没有满足条件的函数,抛异常
		throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
				+ ON_EVENT_METHOD_NAME);
	} else {
		synchronized (methodCache) { // ok,缓存起来
			methodCache.put(key, subscriberMethods);
		}
		return subscriberMethods;
	}
}

这里使用clazz.getDeclaredMethods()来查函数,就是可以查询public、private等函数,但不能访问从其他类继承的方法。那么在下面这里只取public方法了,并且过滤掉abstract、static、bridge、synthetic四种类型,对于abstract与static我们经常看到,那么对于后面两种,对于synthetic,如果经常反编译的会经常看到这个字符,当一个内部类访问外部类的方法时,在内部类就会出现这个字眼;bridge则是java编译器采用bridge方法来兼容本该使用泛型的地方使用了非泛型的用法的。两个都是编译器后面添加的,因此这里也一起过滤掉了。另外只读取参数为一个的函数,如果这些都符合了,那么看是否是下面4种情况:

onEvent:ThreadMode.PostThread 

onEventMainThread:ThreadMode.MainThread

onEventBackgroundThread:ThreadMode.BackgroundThread

onEventAsync:ThreadMode. Async

如果符合就new SubscriberMethod(method, threadMode, eventType),如果不是这4中情况,要么你提前在EventBusBuilder里面skipMethodVerificationFor(skipclass)提前添加这个过滤掉的class,否则这里将抛异常。

查询完毕就将这些装有SubscriberMethod的缓存起来。

好了接着回到上面的subscribe方法,

// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
	Class<?> eventType = subscriberMethod.eventType;<pre name="code" class="java"><span style="white-space:pre">	</span>//subscriptionsByEventType,名字意思很明显,按照eventType来存放subcriptions

 
	CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
	Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
	if (subscriptions == null) { //还没有eventType对应的list
		subscriptions = new CopyOnWriteArrayList<Subscription>(); // ok,生成一个,等下讲下CopyOnWriteArrayList
		subscriptionsByEventType.put(eventType, subscriptions); // 放进map
	} else {
		if (subscriptions.contains(newSubscription)) { //已经存在list,并且newSubscrition也存在,就会抛异常,等下讲下equals

			throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
					+ eventType);
		}
	}

	// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
	// subscriberMethod.method.setAccessible(true);

	int size = subscriptions.size();
	for (int i = 0; i <= size; i++) {
		if (i == size || newSubscription.priority > subscriptions.get(i).priority) { //这里将按照priority来添加
			subscriptions.add(i, newSubscription);
			break;
		}
	}

	List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);// typesBySubscriber按照subscriber存放evenTypes的map

	if (subscribedEvents == null) {
		subscribedEvents = new ArrayList<Class<?>>();
		typesBySubscriber.put(subscriber, subscribedEvents);
	}
	subscribedEvents.add(eventType);

	if (sticky) { // 这里到了sticky,
		if (eventInheritance) { //这个等下将
			// Existing sticky events of all subclasses of eventType have to be considered.
			// Note: Iterating over all events may be inefficient with lots of sticky events,
			// thus data structure should be changed to allow a more efficient lookup
			// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
			Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
			for (Map.Entry<Class<?>, Object> entry : entries) {
				Class<?> candidateEventType = entry.getKey();
				if (eventType.isAssignableFrom(candidateEventType)) {
					Object stickyEvent = entry.getValue();
					checkPostStickyEventToSubscription(newSubscription, stickyEvent);
				}
			}
		} else { //其实sticky单独放在一个events里面,然后会马上去执行要执行的方法
			Object stickyEvent = stickyEvents.get(eventType);
			checkPostStickyEventToSubscription(newSubscription, stickyEvent); //里面其实就是当stickyEvent不为空的时候,执行postToSubscription,该方法就是要去处理具体的方法了
		}
	}
}
上面代码里面写了解释,这里梳理一下,subscribe()方法就是将SubscribMethod方法放入subscriptionsByEventType,typesBySubscriber这两个map里面。然后如果是sticky,就马上去执行对应的方法。

这里用到CopyOnWriteArrayList,由于对CopyOnWriteArrayList不熟,看了下CopyOnWriteArrayList是ArrayList 的一个线程安全的变体,其中所有可变操作(add、set等等)都是通过对底层数组进行一次新的复制来实现的。可以知道线程安全,但是每次都需要copy操作的,因此开销会比较大。这里register()与unregister()的时候调用,也不算频繁变动,应该关键是线程安全,然后在这里使用。

再看下eventInheritance属性,这个属性其实是针对eventType的,如果这个属性为true时,它会找eventType父类或者继承的接口的对象,然后去调用那些函数。

到此register就讲完了,差不多就是,register的时候,先扫描需要的函数,然后将这些函数分类,以便查找,然后如果是设置sticky为true,就需要马上去执行函数操作。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值