我也看了 event bus 3.0源码

2018.2.11
我也想写一篇关于Eventbus的源码解读:今天动手了,真的是去了解它的内部实现.

EventBus 是greenrobot出品的一个用于Android中事件发布/订阅的库。以前传递对象可能通过接口、广播、文件等等,尤其像同一个 Activity 两个 Fragment 之间采用接口传递对象,十分的麻烦,而且耦合度较高。使用 EventBus 之后,这些将不再是问题。盗用GiHub上EventBus的一张图。 

使用它有三个步骤,上面也写的非常清晰了.
Define events:
public static class MessageEvent { /* Additional fields if needed */ }
Prepare subscribers: Declare and annotate your subscribing method, optionally specify a  thread mode :
@Subscribe ( threadMode = ThreadMode . MAIN ) public void onMessageEvent(MessageEvent event) { /* Do something */ };
还有Register and unregister your subscriber.
EventBus . getDefault() . register( this );
EventBus . getDefault() . unregister( this );
Post events:
EventBus . getDefault() . post( new MessageEvent());

线程模型是什么,首先就是 ThreadMode 类.
public enum ThreadMode {
POSTING,MAIN,MAIN_ORDERED,BACKGROUND,ASYNC
}
你需要指定它是属于哪类线程的.通常我们接收是在Main线程.@ Subscribe来注解,是3.0的新方式,不再用旧的onEventxxx()方法了.
public @ interface Subscribe,这是一个注解类.所以你需要了解注解是什么东西.
然后是 public static EventBus getDefault(){} 这是单例的实现.
接着是注册与反注册:
public void register(Object subscriber)它传入的对象是Object,就是任何对象都可以注册了.
反注册 public synchronized void unregister(Object subscriber)
注册的通过SubscriberMethodFinder类查找:
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder .findSubscriberMethods(subscriberClass);
synchronized ( this ) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
显然是在SubscriberMethodFinder里面存在当前注册的对象了.
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();这是存储类注册的map.
findSubscriberMethods()方法就是先查这个map,没有缓存就再查找:
if ( ignoreGeneratedIndex ) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
这两个查找方法都最后通过findUsingReflectionInSingleClass来处理的.
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState. clazz != null ) {
findState. subscriberInfo = getSubscriberInfo(findState);
if (findState. subscriberInfo != null ) {
SubscriberMethod[] array = findState. subscriberInfo .getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod. method , subscriberMethod. eventType )) {
findState. subscriberMethods .add(subscriberMethod);
}
}
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
先查找方法,查完一轮就findState.moveToSuperclass();转到父类.直到完成.
findUsingReflectionInSingleClass找到所有的方法是非私有的,不是编译器生成的方法.
findState.findState.checkAdd(method, eventType)判断是否可以添加
boolean checkAdd(Method method, Class<?> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
}
这里的注释非常清楚了,先判断事件类型,这个比较快,如果不存在,就要判断完整的签名.毕竟有很多重载的方法.
查找到这差不多了,然后释放资源 getMethodsAndRelease(findState);
另一路查找 if (findState. subscriberInfo != null ) {}这个大概是编译器annotationProcessor会产生一些信息.如果编译期就可以确定了,显然要比反射快一些.(?本人未证明是如此,只是猜测)
查找的结果是这个对象:
class SubscriberMethod {
final Method method ; 作用的方法
final ThreadMode threadMode ; 线程
final Class<?> eventType ; 事件
final int priority ; 优先级
final boolean sticky ; 是否粘性
/** Used for efficient comparison */
String methodString ; 只用于比较
}
查找完就注册了:注册就是对观察者处理.将观察者添加到一个列表中,将事件也添加到一个列表中.以便后面的发送事件使用.
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod. eventType ;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType .get(eventType);
//为每一个事件,提供一个CopyOnWriteArrayList来存储,这种列表,多线程读写性能好.读不加锁.
if (subscriptions == null ) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType .put(eventType, subscriptions);
} else {
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 ;
}
}

List<Class<?>> subscribedEvents = typesBySubscriber .get(subscriber);
if (subscribedEvents == null ) {
subscribedEvents = new ArrayList<>();
typesBySubscriber .put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//这里一个订阅者,对应一些事件列表,一个事件,可能对应多个订阅者.经过上面两步,就都完成了.通过不断地注册,系统中可能存在很多注册者.这些事件还按优先级顺序发送.

//如果接收sticky事件,立即分发sticky事件
if (subscriberMethod. sticky ) {
...
Object stickyEvent = stickyEvents .get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
....
}
}
//事件所有订阅列表
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType ;
//一个订阅者的所有事件集
private final Map<Object, List<Class<?>>> typesBySubscriber ;
通过上面的流程可以看出,如果你注册了,但没有反注册,系统中的这些事件,与订阅者会越来越多,内存占用也越多,会导致内存泄露.但如果不断地注册与反注册,同样会有这些重复操作.如果在onstart里注册,这种显然不是太适合了.
发送事件:
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState .get();
//ThreadLocal<PostingThreadState> currentPostingThreadState,这是一个 ThreadLocal对象,找到当前的线程关联的状态.
//然后根据是否在发送状态处理.
List<Object> eventQueue = postingState. eventQueue ;
eventQueue.add(event);

if (!postingState. isPosting ) {
postingState. isMainThread = isMainThread();
postingState. isPosting = true ;
if (postingState. canceled ) {
throw new EventBusException( "Internal error. Abort state was not reset" );
}
//未发送状态,就开始发送,一个一个事件.发送的线程是指定线程.
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove( 0 ), postingState);
}
} finally {
postingState. isPosting = false ;
postingState. isMainThread = false ;
}
}
}
//发送单个事件
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false ;
if ( eventInheritance ) { //处理继承的事件
List<Class<?>> eventTypes = lookupAllEventTypes (eventClass);
int countTypes = eventTypes.size();
for ( int h = 0 ; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
...订阅异常了.没找到结果处理
if (!subscriptionFound) {
// ...
if ( sendNoSubscriberEvent && eventClass != NoSubscriberEvent. class &&
eventClass != SubscriberExceptionEvent. class ) {
post( new NoSubscriberEvent( this , event));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized ( this ) {
subscriptions = subscriptionsByEventType .get(eventClass);
}
找到所有的订阅源.然后发送
for (Subscription subscription : subscriptions) {
postingState. event = event;
postingState. subscription = subscription;
boolean aborted = false ;
try {
postToSubscription(subscription, event, postingState. isMainThread );
aborted = postingState. canceled ;
}
......
}
最后线程分发
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription. subscriberMethod . threadMode ) {
case POSTING :
invokeSubscriber(subscription, event);
break ;
case MAIN :
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster .enqueue(subscription, event);
}
break ;
case MAIN_ORDERED :
if ( mainThreadPoster != null ) {
mainThreadPoster .enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break ;
case BACKGROUND :
if (isMainThread) {
backgroundPoster .enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break ;
case ASYNC :
asyncPoster .enqueue(subscription, event);
break ;
default :
throw new IllegalStateException( "Unknown thread mode: " + subscription. subscriberMethod . threadMode );
}
}
这个方法,根据注解,用不同的线程去发送事件.没什么要解释的.在添加注解时,就决定了它处于什么线程了, MAIN在android里比较关注的主线程.它的实现是 HandlerPoster.看到Handler就知道,它是最终发送到主线程队列中.
到这,分发的流程就结束了:

EventBus#Post() 也只做了三件事
1. 根据订阅事件在 subscriptionsByEventType 中查找相应的订阅者
2. 分发订阅者的订阅事件调用线程
2. 通过反射调用订阅者的订阅事件

典型的观察者模式的应用.
这里需要的知识是ThreadLocal,它用于获取当前的线程.
ExecutorService线程池.在BackgroundPoster与AsyncPoster中用它发送事件.
其实它已经解决了一个问题,发送一个事件,可以到指定的线程中去做事,这其中的线程切换是我们需要关注的.这当然只是固定的模式,订阅线程是在开始就固定了.不像rxjava一样线程切换那么复杂.

反注册也可以理解了.就是把上面查找的两个列表清空了.
typesBySubscriber与subscriptionsByEventType里面相关的数据清除.

一般分析到这里就行了,但我并不想这样,因为里面还有一些比较重要的概念.流程,原理差不多就是上面的部分了.
注册(查找事件并添加),发送(查找对象,逐个发送),取消(查找事件并移除)

Poster各种发送器都有什么呢?它是一个接口,只有一个方法 void enqueue(Subscription subscription, Object event);
这里的发送器有PendingPostQueue这个对象,它包含了要发送的事件列表.这个列表又包含了PendingPost pendingPost = PendingPost. obtainPendingPost (subscription, event);
有没有相似的感觉.这和系统的handler,message类似的.
非主线程是: eventBus .getExecutorService().execute( this );运行在线程池中.
主线程则是在handleMessage(Message msg) {}中处理的.

最后就是如何构建一个总线了
EventBusBuilder,建造者模式.
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport .createPoster( this ) : null ;
backgroundPoster = new BackgroundPoster( this );
asyncPoster = new AsyncPoster( this );
indexCount = builder. subscriberInfoIndexes != null ? builder. subscriberInfoIndexes .size() : 0 ;
subscriberMethodFinder = new SubscriberMethodFinder(builder. subscriberInfoIndexes ,
builder. strictMethodVerification , builder. ignoreGeneratedIndex );
logSubscriberExceptions = builder. logSubscriberExceptions ;
logNoSubscriberMessages = builder. logNoSubscriberMessages ;
sendSubscriberExceptionEvent = builder. sendSubscriberExceptionEvent ;
sendNoSubscriberEvent = builder. sendNoSubscriberEvent ;
throwSubscriberException = builder. throwSubscriberException ;
eventInheritance = builder. eventInheritance ;
executorService = builder. executorService ;
}
AsyncPoster与BackgroundPoster主要区别在于,前者是一次性的,后者是不断循环.如果执行失败了,还可以下次执行.像在后台的感觉.

参考:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值