前几篇文章分析了Activity的源码,后来看了看Window以及ViewRoot的相关源码,这些只是还没梳理,真的是视觉疲劳,来一个EventBus源码分析压压惊~。
其实关于EventBus的源码分析,网上也有很多,但是终究是别人的,以前也看过很多遍,但是决定是自己写下来比较好,座右铭:看一遍,不如自己写一遍。
关于EventBus的小总结我们先看下,带着知识点去看源码,然后分析为什么要这么写,还是必须这样写。
- POSTING:发布事件和订阅事件总是在一个线程。避免操作UI,可能造成ANR。
- MAIN : 无论发布事件位于什么线程,订阅事件总是在UI主线程
- BACKGROUND: 发布事件位于子线程,那么订阅事件就位于该子线程;如果发布事件位于Ui主线程,那么订阅事件就另外开启一个子线程。订阅事件方法中不能更新UI。
- ASYNC:无论发布事件位于什么线程,订阅事件总是位于另外在开启子线程。
- EventBus索引的添加
- 有这样一个场景:我们的EventModel A 继承自EventModel B,并实现了接口EventInterface C,此时在订阅类中,三个订阅方法参数分别为:EventModel A, EventModel B , EventInterface;最后在发布事件 EventModel A, 此时的结果应该是:三个订阅方法都能够收到事件。但是如果我们只想让参数为EventModel A订阅方法收到事件,应该怎么做? 详情看代码描述
- EventBus发送粘性事件,等等,说一下粘性时间,ActivityA 先创建,然后发送粘性事件,然后创建并跳转到ActivityB,此时在ActivityB注册了粘性事件的回调方法,此时粘性回调方法将执行,这是什么原理?
- 同一个订阅类如果注册两次为什么报错?
问题点6代码描述:
@Subscribe(threadMode = ThreadMode.MAIN , sticky = true)
public void onEventObject(EventModelA object) {
Log.e("-----------","我是子类");
}
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onEventObject(EventModelB event) {
Log.e("-----------","我是父类");
}
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onEventObject(EventInterfaceC event) {
Log.e("-----------","我是父接口");
}
EventBus.getDefault().postSticky(new EventModelA ());
EventBus 的 register(this) 方法
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
/*
翻译:注册给定的订阅服务用于接收事件,订阅者必须调用unregister取消注册对象。
订阅服务器有事件处理方法,这些方法需要有ThreadModel(线程模式)和优先级的配置
*/
public void register(Object subscriber) {
//获取订阅者的Class对象
Class<?> subscriberClass = subscriber.getClass();
//通过这个类对象获取SubscriberMethod的集合,至于集合是什么后面讲到。
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
//遍历SubscriberMethods集合,执行subscribe方法,参数为:订阅者的类和subscriberMethod。
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
register的注释翻译,这个不需要解释了, 方法内,先获取了订阅类的Class对象,把这个Class对象为参数,通过
findSubscriberMethods(Class) 方法获取到List集合泛型为SubscriberMethod, 从findSubscriberMethods方法名来看,就是:找到订阅的方法。 至于这个方法是怎么工作的我们下文分析。有必要看下SubscriberMethod类了:
/** Used internally by EventBus and generated subscriber indexes. */
public class SubscriberMethod {
final Method method; //Java通过反射获取到的订阅类的信息
final ThreadMode threadMode; //订阅类中订阅方法的线程模型TreadMode
final Class<?> eventType; //订阅方法参数的Class对象,也就是我们的Model的Class对象
final int priority; //订阅回调方法的优先级
final boolean sticky; //订阅回调方法是否是粘性的
/** Used for efficient comparison */
String methodString; //订阅方法的方法名
.........
通过代码可以看出 SubscriberMethod 其实就是一个Model类,它代表了:某一个订阅类的订阅方法信息。
那么回过头看下findSubscriberMethods(Class)就是:返回某一个注册订阅类的订阅方法的集合。然后接下来遍历这个集合,执行subscribe方法,参数为:订阅类(subscriber)和其某一个订阅的方法(subscriberMethod);
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//获得订阅方法的Class对象。
Class<?> eventType = subscriberMethod.eventType;
//创建Subscription,参数为:订阅者(subscriber)和订阅方法的信息类(subscriberMethod)
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//subscriptionsByEventType获得CopyOnWriteArrayList集合,泛型为Subscription
//eventType就是注册回调方法类的参数的Class对象,也就是上述例子中的:EventModelA的Class对象
//subscriptions也就是所有包含该回调方法的订阅类和该回调方法的信息集合
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
//以该参数Class为Key值的Value是null,也就是同一进程中这是这个订阅类是第一个使用该Model为参数的回调方法
subscriptions