您的位置:首页 > 其它

EventBus要点和源码解析

2018-01-12 11:50 281 查看
转载请注明链接:http://blog.csdn.net/feather_wch/article/details/79042406

总结EventBus的知识点

分析EventBus源码的要点,包括:

1. EventBus的构造源码

2. 订阅者注册的源码

3. 事件发送的源码

4. 订阅者取消注册的源码

EventBus要点和源码解析

版本:2018/2/11-1

EventBus要点和源码解析
EventBus的构造

订阅者注册

事件的发送

订阅者取消注册

1、事件总线的作用

简化Activity、Fragment、Thread和Service之前的通信并且有更高的质量

2、EventBus作用和优缺点

针对android优化的发布-订阅事件总线。

开销小,相比于广播效率高(广播如果传递实体数据,需要序列化)

将发送者和接受者解耦

3、EventBus三要素

Event事件

SubScriber:事件订阅者。EventBus3.0开始可以指定任意事件处理方法,只需要添加一个注解@Subscribe并且指定线程模型(默认为POSTING)

Publisher:事件发布者,直接调用EventBus的post(Object)方法

4、EventBus的四种线程模型

ThreadMode作用备注
POSTING(默认)哪个线程发布事件,处理函数就在哪个线程处理事件处理时要避免执行耗时操作,会阻塞事件的传递,甚至导致ANR
MAIN事件在UI线程中处理避免耗时操作
BACKGROUND若事件在UI线程发布,则事件在新线程处理;若事件在子线程发布,则直接在该线程处理禁止UI操作
ASYNC无论事件在哪发布,事件都在新子线程中处理禁止UI操作
5、EventBus3.0前的只能使用规定的消息处理方法(对应线程模型)

onEvent

onEventMainThread

onEventBackgroundThread

onEventAsync

6、EventBus的使用

自定义一个事件类,如:
class MsgEvent


在需要订阅事件的地方注册事件:
EventBus.getDefault().register(this)


发送事件:
EventBus.getDefault().post(msgEvent)


处理事件

@Subscribe
public void onEventMainThread(MsgEvent event)
{
...
}
//Since EventBus 3.0
@Subscribe (threadMode = ThreadMode.MAIN)
public void customEventHandler(MsgEvent event)
{
...
}


取消事件订阅:
EventBus.getDefault().unregister(this)


7、ProGuard需要加入EventBus相关的混淆规则

8、EventBus的粘性事件

是指发送事件后,再订阅该事件也可以接收到该事件(类似于粘性广播)

9、EventBus粘性事件的处理和发送

@Subscribe (threadMode = ThreadMode.MAIN, sticky = true)
public void customStickyEventHandler(MsgEvent event)
{
...
}


发送:

EventBus.getDefault().postSticky(new MsgEvent("粘性事件"));


EventBus的构造

10、EventBus的构造方法

//1. 单例模式,双重检查
public static EventBus getDefault() {
if(defaultInstance == null) {
Class var0 = EventBus.class;
synchronized(EventBus.class) {
if(defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
//2. 建造者模式
public EventBus() {
this(DEFAULT_BUILDER);
}
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();


getDefault采用单例模式,使用双重检查(DLC)

EventBus的构造方法里面,通过默认EvenBusBuilder进行构造(建造者模式)

我们可以通过构造一个EvenBusBuilder对EventBus进行配置

订阅者注册

11、EventBus的注册源码要点:

//EventBus的订阅者注册
public void register(Object subscriber) {
Class subscriberClass = subscriber.getClass();
//1. 获取订阅者所有的需要订阅的方法(SubscriberMethod中保存了订阅方法的Method对象、线程模式、事件类型、优先级、是否粘性事件等属性)
List subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized(this) {
Iterator var5 = subscriberMethods.iterator();

//2. 遍历所有需要订阅的方法,并进行注册
while(var5.hasNext()) {
SubscriberMethod subscriberMethod = (SubscriberMethod)var5.next();
this.subscribe(subscriber, subscriberMethod);
}

}
}


12、EventBus注册的findSubscriberMethods源码要点

/**
* 获取订阅者的所有订阅方法(onEventMainThread等等)
*/
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//1. 查找是否有缓存的订阅方法的集合
List subscriberMethods = (List)METHOD_CACHE.get(subscriberClass);
//2. 找到方法立即返回
if(subscriberMethods != null) {
return subscriberMethods;
} else {
//3. 选择采取何种方法查询订阅方法的集合(ignoreGeneratedIndex指是否忽略注解器生成的MyEventBusIndex,默认值false)
if(this.ignoreGeneratedIndex) {
subscriberMethods = this.findUsingReflection(subscriberClass);
} else {
//4. 默认通过单例模式获取默认的EventBus对象(ignoreGeneratedIndex=false)
subscriberMethods = this.findUsingInfo(subscriberClass);
}

//5.获取订阅方法集合后,放入缓存中
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;
}
}
}


13、EventBus注册的findUsingInfo源码要点

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
SubscriberMethodFinder.FindState findState = this.prepareFindState();
findState.initForSubscriber(subscriberClass);

for(; findState.clazz != null; findState.moveToSuperclass()) {
//1. 获取订阅者信息(默认没有忽略注解器生成的MyEventBusIndex,下面会进行判断)
findState.subscriberInfo = this.getSubscriberInfo(findState);
//2. 判断是否配置了MyEventBusIndex,若配置了Info不为空
if(findState.subscriberInfo != null) {
//4. 通过订阅者信息获得订阅方法的相关信息
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
SubscriberMethod[] var4 = array;
int var5 = array.length;

for(int var6 = 0; var6 < var5; ++var6) {
SubscriberMethod subscriberMethod = var4[var6];
if(findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//3. 没有配置MyEventBusIndex,会将订阅方法保存到findState中
this.findUsingReflectionInSingleClass(findState);
}
}
//5. 对findState进行回收处理并且返回订阅方法的List集合
return this.getMethodsAndRelease(findState);
}


14、EventBus注册的findUsingReflectionInSingleClass源码要点

private void findUsingReflectionInSingleClass(SubscriberMethodFinder.FindState findState) {
Method[] methods;
try {
//1. 通过反射来获得订阅者中的所有方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable var12) {
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
...
//2. 根据方法的类型、参数和注解找到订阅方法
...
//3. 将找到的订阅方法的相关信息保存到findState中
if(findState.checkAdd(method, eventType)) {
ThreadMode threadMode = methodName1.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, methodName1.priority(), methodName1.sticky()));
}
...
}


15、EventBus注册的subscribe(订阅者注册)源码要点

/**======================================================
*  订阅者的注册
*  @位于: EventBus的register()
*  @本质思想:
*    1. 将订阅者对象添加到[订阅者对象集合]中(根据订阅方法的优先级)-进行注册
*        [订阅者对象集合]需要根据[事件类型]添加到[按事件类型分类的总订阅者对象集合]中(subscriptionsByEventType)
*    2. 将事件类型添加到[事件类型集合]中
*        [事件类型集合]需要根据[订阅者]添加到[按订阅者分类的总事件类型集合]中(typesBySubscriber)
*    3. 对粘性事件进行额外处理
*=======================================================*/
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class eventType = subscriberMethod.eventType;
//1. 根据订阅者(subscriber)和订阅方法(subscriberMethod)创建一个订阅对象(Subscription)
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//2. 根据事件类型(EventType)获取订阅对象集合
CopyOnWriteArrayList subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventType);
//3. 订阅对象集合为空,则重新创建集合,并将subscriptions根据事件类型eventType保存到subscriptionsByEventType集合中
if(subscriptions == null) {
subscriptions = new CopyOnWriteArrayList();
this.subscriptionsByEventType.put(eventType, subscriptions);
} else if(subscriptions.contains(newSubscription)) {
//4. 判断订阅者是否已经被注册
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
}

int size = subscriptions.size();

//5. 将订阅者对象添加到订阅者对象集合中
for(int subscribedEvents = 0; subscribedEvents <= size; ++subscribedEvents) {
if(subscribedEvents == size || subscriberMethod.priority > ((Subscription)subscriptions.get(subscribedEvents)).subscriberMethod.priority) {
// 根据订阅方法的优先级进行注册
subscriptions.add(subscribedEvents, newSubscription);
break;
}
}

//6. 通过subscriber获取事件类型集合(subscribedEvents)
Object subscribedEvents = (List)this.typesBySubscriber.get(subscriber);
if(subscribedEvents == null) {
subscribedEvents = new ArrayList();
//7. 事件类型集合为null,则新建,并根据订阅者subscriber将subscribedEvents存储到typesBySubscriber(Map集合)中
this.typesBySubscriber.put(subscriber, subscribedEvents);
}

//8. 将eventType添加到subscribedEvent中
((List)subscribedEvents).add(eventType);

//9. 如果是粘性事件,从stickyEvents事件保存队列中取出该事件类型的事件发送给当前订阅者
if(subscriberMethod.sticky) {
if(this.eventInheritance) {
Set stickyEvent = this.stickyEvents.entrySet();
Iterator var9 = stickyEvent.iterator();

while(var9.hasNext()) {
Entry entry = (Entry)var9.next();
Class candidateEventType = (Class)entry.getKey();
if(eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent1 = entry.getValue();
this.checkPostStickyEventToSubscription(newSubscription, stickyEvent1);
}
}
} else {
Object var14 = this.stickyEvents.get(eventType);
this.checkPostStickyEventToSubscription(newSubscription, var14);
}
}

}


事件的发送

16、EventBus的post方法的源码要点

public void post(Object event) {
//1. PostingThreadState保存事件队列和线程状态信息
EventBus.PostingThreadState postingState = (EventBus.PostingThreadState)this.currentPostingThreadState.get();
//2. 获取事件队列
List eventQueue = postingState.eventQueue;
//3. 将当前事件插入事件队列
eventQueue.add(event);
if(!postingState.isPosting) {
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;
if(postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}

try {
//4. 处理事件队列中所有事件, 并移除该事件
while(!eventQueue.isEmpty()) {
this.postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}


17、EventBus事件发送的postSingleEvent源码要点

private void postSingleEvent(Object event, EventBus.PostingThreadState postingState) throws Error {
Class eventClass = event.getClass();
boolean subscriptionFound = false;
//1. 表示是否向上查找事件的父类,默认为true(可以通过EventBuilder配置)
if(this.eventInheritance) {
//2. 找到所有父类事件,保存在List中
List eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();

for(int h = 0; h < countTypes; ++h) {
Class clazz = (Class)eventTypes.get(h);
//3. 通过postSingleEventForEventType对事件逐一处理
subscriptionFound |= this.postSingleEventForEventType(event, postingState, clazz);
}
} else {
//4. 没有查找父类事件, 直接处理该事件
subscriptionFound = this.postSingleEventForEventType(event, postingState, eventClass);
}

if(!subscriptionFound) {
if(this.logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if(this.sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) {
this.post(new NoSubscriberEvent(this, event));
}
}
}


18、EventBus事件发送的postSingleEventForEventType源码要点

/**==============================
*  按照事件类型post事件
*==============================*/
private boolean postSingleEventForEventType(Object event, EventBus.PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized(this) {
//1. 从[按事件类型分类的总订阅对象集合]中获取订阅对象集合(与该事件对应)
subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventClass);
}

if(subscriptions != null && !subscriptions.isEmpty()) {
Iterator var5 = subscriptions.iterator();

//2. 遍历订阅对象集合,分别处理
while(var5.hasNext()) {
Subscription subscription = (Subscription)var5.next();
//3. postingState获得事件和订阅对象
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;

try {
//4. 对事件进行处理
this.postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}

if(aborted) {
break;
}
}

return true;
} else {
return false;
}
}


19、EventBus事件发送的postToSubscription源码要点

/**==================================
*        发送给订阅对象
*  @要点:
*     1. invokeSubscriber()-通过反射直接运行订阅的方法
*     2. mainThreadPoster.enqueue()-是将订阅事件添加到主线程队列中
*           类型为HandlerPoster,继承自Handler,通过Handler将订阅方法却环岛主线程执行。
*     3. backgroundPoster.enqueue()-新开子线程处理
*     4. asyncPoster.enqueue()-新开子线程处理
*==================================*/
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
//1. 取出订阅方法的线程模式[subscription.subscriberMethod.threadMode]
switch(subscription.subscriberMethod.threadMode) {
//2. 根据模式分别处理
case POSTING:
//3. 与事件发布处在同一线程
this.invokeSubscriber(subscription, event);
break;
case MAIN:
//4. 在UI线程
if(isMainThread) {
this.invokeSubscriber(subscription, event);
} else {
this.mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
//5. 事件发布处若在UI线程,则新开子线程处理。若在子线程,则在该线程处理
if(isMainThread) {
this.backgroundPoster.enqueue(subscription, event);
} else {
this.invokeSubscriber(subscription, event);
}
break;
case ASYNC:
//6. 无论是否在UI线程,均新开子线程处理
this.asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}

}


订阅者取消注册

20、订阅者取消注册的unregister源码要点

public synchronized void unregister(Object subscriber) {
//1. 通过订阅者(subscriber)从[按订阅者分类的 事件类型集合的总集合中]中获取相应[事件类型集合]
List subscribedTypes = (List)this.typesBySubscriber.get(subscriber);
if(subscribedTypes != null) {
Iterator var3 = subscribedTypes.iterator();

while(var3.hasNext()) {
Class eventType = (Class)var3.next();
//2. 通过[事件类型]在[订阅对象集合]中移除该订阅者的订阅对象
this.unsubscribeByEventType(subscriber, eventType);
}
//3. [事件类型集合的总集合]中移除与订阅者相关的事件类型集合
this.typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}


21、订阅者取消注册的unsubscribeByEventType源码要点

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//1. 通过事件类型获取订阅对象集合
List subscriptions = (List)this.subscriptionsByEventType.get(eventType);
if(subscriptions != null) {
int size = subscriptions.size();

for(int i = 0; i < size; ++i) {
//2. 移除与订阅者(subscriber)相关的订阅对象
Subscription subscription = (Subscription)subscriptions.get(i);
if(subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
--i;
--size;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  EventBus 事件总线