Android EventBus 源码解析
2017-12-04 17:59
337 查看
EventBus,由greenrobot组织贡献(该组织还贡献了greenDAO),一个Android事件发布/订阅轻量级框架;
进程内EventBus可以代替Android传统的Intent,Handler,Broadcast或接口函数,在Fragment,Activity,Service线程之间传递数据,执行方法;
github地址 https://github.com/greenrobot/EventBus 点击打开链接
在没有它之前,进程内通信一直都是用的广播来发送接收消息,后来用了后发现真的是太方便了,而且还是轻量级的,最近研究了下它的源码,
学习了下大神牛逼的架构和思维,确实很厉害,为啥我没想到呢。
怎么使用的就不做介绍了,相信大家都会用,下面直接进入正文
先看下源码结构,如图:
代码量其实不是很多,很多类里面就只有一点代码,前面3个文件目录都是一些辅助工具类,不是核心,有空可以去学习下,
这里只解析主干逻辑。
平时我们主要用这几个方法:注册订阅者,注销订阅者,定义订阅方法,post事件,所以就从这几个方面开始解析
首先我们知道EventBus用的是单例模式,整个进程中只会有一个EventBus的实例
这里加上同步,防止多线程调用getDefault()时出现几个实例
接下来看下定义订阅方法
平时就是这么定义的订阅方法,为啥要这么写呢,我们先看下这个注解@Subscribe
这个定义的注解包含了3个方法,都有默认值,订阅方法所在线程、是否开启粘性事件模式、优先级
为啥要定义这么一个注解呢?
问题先放这,后面揭晓,接下来看下注册订阅者方法register()
当前订阅者register传入进来,拿到它的Class对象,根据这个Class对象获取register的订阅方法,看下这些订阅方法如何被获取的
可以看到调用了findUsingReflection()或者findUsingInfo(),ignoreGeneratedIndex默认是false,那么就会直接调用findUsingReflection(),继续往下看
findUsingReflectionInSingleClass()反射获取订阅方法,看到这知道为啥要用注解@Subcribe了吧,因为一个类那么多方法,怎么知道哪些方法是订阅方法呢,就是用这个注解作为标识
到这里,这个订阅者的方法都以List的形式返回了,接着回到register()
接下来就是开始循环把这些订阅方法一个一个的注册了,看下subscribe()
这个方法还挺长的,解析我都写在代码里面了,逻辑还是挺复杂的
跟EventBus这个类的这几个成员变量有关,这几个集合的作用主要是用来存储,具体什么作用我都解释了,这个订阅方法的核心
把事件和订阅者相关的方法存储在subscriptionsByEventType 里面,因为一个事件可能在很多地方都注册过,最后还有一个粘性事件
sticky的处理,什么是粘性事件,比如这个事件在A页面发送完毕了,一般情况下注册过的地方就会马上接受到这个事件处理掉,
然后打开过注册了这个事件的B页面的时候,是不会再接受到这个事件的,而粘性事件就相反,打开B页面同样会接受到这个事件,
可以看下源码
这里才刚开始注册事件,就调用了postToSubscription()去发布事件,postToSubscription()就是post事件的方法,这个方法后面会讲到,到这里注册就算解析完了,估计客观们都晕了,哈哈,我就用一句话概括下:
注册事件其实就是用一个HashMap subscriptionsByEventType 把事件和注册了事件相关的类和方法储存起来,方便后面post(事件)使用。
接下来看下post()方法,
TheadLocal不是很清楚的小伙伴可以移步到这,
ThreadLocal源码解析
http://blog.csdn.net/msn465780/article/details/78673656 点击打开链接
PostingTheadState是一个静态类内部太监类,说白了就是一个实体,用来存储当前线程和post事件的一些状态。
一开始是存储post的事件,因为可能有很多地方都在post,接下来循环调用postSingleEvent(),
代码核心是调用postSingleEventForEventType()
哈哈,看到了吧,根据事件的Class对象subscriptionsByEventType.get(eventClass) 获取到相关的订阅者和方法,subscriptionsByEventType 还熟悉吗?就是register的时候用来保存的那个HashMap,那到这个方法后干啥呢?调用
postToSubscription(),这个方法还熟悉吗?前面粘性事件Sticky中提到过,就是用的它,是它是它就是它!
switch语句根据订阅方法的时候,注解中指定线程,分别post事件,一个一个的讲下为啥这么区分,先看下都用到的方法invokeSubscriber(),
订阅方法的Method对象调用invoke(),是一种反射机制,参数中知道了订阅者对象,订阅者方法的事件参数对象,那么就可以直接调用到这个订阅方法了,也就达到发送事件接受到事件的循环了。
POSTING
未指定订阅方法线程的时候默认值,直接调用,post在哪个线程,这个订阅方法就在哪个线程
MAIN
指定订阅方法在UI线程中执行,如果当前为UI线程直接调用,否则利用MainThreadSupport对象加入UI线程消息队列 末尾执行,MainThreadSupport其实就是主线程的Handler对象,后面再讲
MAIN_ORDERED
这个和MAIN有啥区别呢?其实区别就是如果MainThreadSupport存在会优先加入UI线程消息队列末尾,否则才是立即执行
BACKGROUND
如果当前为主线程,加入后台线程执行,否则立即执行
ASYNC
不管当前什么线程,都在后台执行
post主干逻辑基本都说完了,再说下刚才那几个poster,MainThreadSupport、BackgroundPoster、AsyncPoster
他们都是接口,继承于Poster。
MainThreadSupport
作用就是把post加入到UI线程消息队列末尾执行
BackgroundPoster
创建了一个线程池,然后在后台中执行
AsyncPoster
跟BackgroundPoster相似
接下来看下注销事件
我们安卓中一般都会在Activity或者Fragment注册事件,如果不注销肯定会发生内存泄漏,导致内存溢出,
unregister()
其实我都不用解析了,还记得开始我提到过EventBus有几个成员变量,都是容器类,typesBySubscriber用于判断是否注册过,
subscriptionsByEventType这个很多地方都出现过,保存事件及对应订阅方法的,注销其实就是把这个订阅者和相关方法移除掉,
哈哈,是不是想到判断当前是否注册过的那个方法了,看下源码
明白了吧!
到这里EventBus这个优秀的框架主干都解析完了,我可能很多地方没描述清楚,不过小伙伴们懂逻辑原理就行了,细微的方法可以下面慢慢看下了。
EventBus说白了就是根据注解把相关的方法都保存在一个HashMap里面,key为事件Class对象,value为订阅者及相关订阅方法的集合,发送事件的时候就根据这个事件的Class对象从HashMap中拿出来一个一个循环的反射调用订阅者的订阅方法。
好了,又可以愉快玩耍了
进程内EventBus可以代替Android传统的Intent,Handler,Broadcast或接口函数,在Fragment,Activity,Service线程之间传递数据,执行方法;
github地址 https://github.com/greenrobot/EventBus 点击打开链接
在没有它之前,进程内通信一直都是用的广播来发送接收消息,后来用了后发现真的是太方便了,而且还是轻量级的,最近研究了下它的源码,
学习了下大神牛逼的架构和思维,确实很厉害,为啥我没想到呢。
怎么使用的就不做介绍了,相信大家都会用,下面直接进入正文
先看下源码结构,如图:
代码量其实不是很多,很多类里面就只有一点代码,前面3个文件目录都是一些辅助工具类,不是核心,有空可以去学习下,
这里只解析主干逻辑。
平时我们主要用这几个方法:注册订阅者,注销订阅者,定义订阅方法,post事件,所以就从这几个方面开始解析
首先我们知道EventBus用的是单例模式,整个进程中只会有一个EventBus的实例
static volatile EventBus defaultInstance;
/** Convenience singleton for apps using a process-wide EventBus instance. */ public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
这里加上同步,防止多线程调用getDefault()时出现几个实例
接下来看下定义订阅方法
@Subscribe(threadMode = ThreadMode.MAIN) public void refreshUI(RefreshBagEvent event) { } @Subscribe public void loadData(DataChangeEvent event) { }
平时就是这么定义的订阅方法,为啥要这么写呢,我们先看下这个注解@Subscribe
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Subscribe { /** * 指定订阅方法所在线程 * @return */ ThreadMode threadMode() default ThreadMode.POSTING; /** * 是否开启粘性事件 * If true, delivers the most recent sticky event (posted with * {@link EventBus#postSticky(Object)}) to this subscriber (if event available). */ boolean sticky() default false; /** * 优先级 * Subscriber priority to influence the order of event delivery. * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of * delivery among subscribers with different {@link ThreadMode}s! */ int priority() default 0; }
这个定义的注解包含了3个方法,都有默认值,订阅方法所在线程、是否开启粘性事件模式、优先级
为啥要定义这么一个注解呢?
问题先放这,后面揭晓,接下来看下注册订阅者方法register()
/** * 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. */ public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); // 获取订阅者订阅的方法 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); // 加上同步block,可能同时有多处都在注册 synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
当前订阅者register传入进来,拿到它的Class对象,根据这个Class对象获取register的订阅方法,看下这些订阅方法如何被获取的
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else { subscriberMethods = findUsingInfo(subscriberClass); } 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()或者findUsingInfo(),ignoreGeneratedIndex默认是false,那么就会直接调用findUsingReflection(),继续往下看
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findState.subscriberInfo = getSubscriberInfo(findState); // 这里应该是从缓存中获取订阅的方法,不过看源码findState.subscriberInfo永远都是null,所以进不去 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 { // 利用反射获取订阅方法储存在findState里面 findUsingReflectionInSingleClass(findState); } findState.moveToSuperclass(); } // 从findState中获取订阅方法 return getMethodsAndRelease(findState); }
private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { // This is faster than getMethods, especially when subscribers are fat classes like Activities // 获取注册类中所有声明的所有方法,不包括继承或实现的 methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 // 获取注册类中所有公共方法,包括继承或实现的 methods = findState.clazz.getMethods(); findState.skipSuperClasses = true; } for (Method method : methods) { int modifiers = method.getModifiers(); // 过滤掉非public、静态的方法 if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { // 获取方法中参数 Class<?>[] parameterTypes = method.getParameterTypes(); // 如果只有一个参数 if (parameterTypes.length == 1) { // 获取方法中Subscribe注解 Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); // 方法中Subscribe注解不为null if (subscribeAnnotation != null) { Class<?> eventType = parameterTypes[0]; // 检查findState是否添加过这个订阅方法 if (findState.checkAdd(method, eventType)) { ThreadMode threadMode = subscribeAnnotation.threadMode(); findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } 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); } } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { // 抛出异常,订阅的方法必须是public,不带static、abstract的 String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } }
findUsingReflectionInSingleClass()反射获取订阅方法,看到这知道为啥要用注解@Subcribe了吧,因为一个类那么多方法,怎么知道哪些方法是订阅方法呢,就是用这个注解作为标识
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) { List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods); // 回收findState的数据 findState.recycle(); synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { if (FIND_STATE_POOL[i] == null) { FIND_STATE_POOL[i] = findState; break; } } } return subscriberMethods; }
到这里,这个订阅者的方法都以List的形式返回了,接着回到register()
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); // 获取订阅者订阅的方法 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); // 加上同步block,可能同时有多处都在注册 synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
接下来就是开始循环把这些订阅方法一个一个的注册了,看下subscribe()
// Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { // 获取事件.class对象 Class<?> eventType = subscriberMethod.eventType; // 创建一个含有订阅者和订阅方法的订阅实体 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); // 根据事件类型获取订阅实体集合,CopyOnWriteArrayList是线程安全的 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { // 如果subscriptionsByEventType还没有事件.class对象eventType相关的订阅实体集合,就new 一个 subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { // 如果subscriptionsByEventType有eventType相关的订阅实体集合,且包含newSubscription,抛出异常已经注册过了 if (subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } // 把newSubscription添加到subscriptions集合中,默认优先级的情况下添加到末尾;优先级越大添加越靠前 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; } } // typesBySubscriber用于判断是否注册过某个订阅者 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); // sticky默认false if (subscriberMethod.sticky) { // eventInheritance 默认为true // 如果eventType代表的类或者接口是candidateEventType代表的类或者接口或者父类父接口,也要post事件 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 { Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } } }
这个方法还挺长的,解析我都写在代码里面了,逻辑还是挺复杂的
/** * 储存事件及父类父接口Class对象; * key:事件Class对象,value:事件及父类父接口Class对象 */ private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>(); /** * 储存事件及对应方法; * key是事件的Class对象,value是订阅者及订阅的方法集合 */ private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; /** * 储存订阅者及事件Class对象; * 用于判断订阅者是否注册过 */ private final Map<Object, List<Class<?>>> typesBySubscriber; /** * 存储粘性事件; * 用于postSticky() */ private final Map<Class<?>, Object> stickyEvents; private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { // 初始化一个PostingThreadState对象 return new PostingThreadState(); } };
跟EventBus这个类的这几个成员变量有关,这几个集合的作用主要是用来存储,具体什么作用我都解释了,这个订阅方法的核心
把事件和订阅者相关的方法存储在subscriptionsByEventType 里面,因为一个事件可能在很多地方都注册过,最后还有一个粘性事件
sticky的处理,什么是粘性事件,比如这个事件在A页面发送完毕了,一般情况下注册过的地方就会马上接受到这个事件处理掉,
然后打开过注册了这个事件的B页面的时候,是不会再接受到这个事件的,而粘性事件就相反,打开B页面同样会接受到这个事件,
可以看下源码
// sticky默认false if (subscriberMethod.sticky) { // eventInheritance 默认为true // 如果eventType代表的类或者接口是candidateEventType代表的类或者接口或者父类父接口,也要post事件 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 { Object stickyEvent = stickyEvents.get(eventType); checkPostStickyEventToSubscription(newSubscription, stickyEvent); } }
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) { if (stickyEvent != null) { // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state) // --> Strange corner case, which we don't take care of here. postToSubscription(newSubscription, stickyEvent, isMainThread()); } }
这里才刚开始注册事件,就调用了postToSubscription()去发布事件,postToSubscription()就是post事件的方法,这个方法后面会讲到,到这里注册就算解析完了,估计客观们都晕了,哈哈,我就用一句话概括下:
注册事件其实就是用一个HashMap subscriptionsByEventType 把事件和注册了事件相关的类和方法储存起来,方便后面post(事件)使用。
接下来看下post()方法,
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { // 初始化一个PostingThreadState对象 return new PostingThreadState(); } };
/** Posts the given event to the event bus. */ public void post(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); List<Object> eventQueue = postingState.eventQueue; // 添加事件event对象 eventQueue.add(event); // 状态是否为posting,如果没有,则开启 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()) { // 循环开始post事件,每post一个事件,就从eventQueue中移除一个事件对象 postSingleEvent(eventQueue.remove(0), postingState); } } finally { // 最终恢复默认值 postingState.isPosting = false; postingState.isMainThread = false; } } }
TheadLocal不是很清楚的小伙伴可以移步到这,
ThreadLocal源码解析
http://blog.csdn.net/msn465780/article/details/78673656 点击打开链接
/** For ThreadLocal, much faster to set (and get multiple values). */ final static class PostingThreadState { final List<Object> eventQueue = new ArrayList<>(); boolean isPosting; boolean isMainThread; Subscription subscription; Object event; boolean canceled; }
PostingTheadState是一个静态类内部太监类,说白了就是一个实体,用来存储当前线程和post事件的一些状态。
一开始是存储post的事件,因为可能有很多地方都在post,接下来循环调用postSingleEvent(),
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; // eventInheritance默认为true 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 (logNoSubscriberMessages) { // post事件,但是没有地方注册就打印出提示日志 logger.log(Level.FINE, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { // 不知道为啥还要执行以下代码,既然没有注册这个事件还去post一个未被注册的新事件,不是形成了递归吗? post(new NoSubscriberEvent(this, event)); } } }
代码核心是调用postSingleEventForEventType()
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { // 从储存regist的方法中获取事件对应的方法 subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { // 开始循环把同一个事件post到注册者,意思就是调用这个事件订阅的方法 for (Subscription subscription : subscriptions) { postingState.event = event; postingState.subscription = subscription; boolean aborted = false; try { postToSubscription(subscription, event, postingState.isMainThread); aborted = postingState.canceled; } finally { postingState.event = null; postingState.subscription = null; postingState.canceled = false; } if (aborted) { break; } } return true; } return false; }
哈哈,看到了吧,根据事件的Class对象subscriptionsByEventType.get(eventClass) 获取到相关的订阅者和方法,subscriptionsByEventType 还熟悉吗?就是register的时候用来保存的那个HashMap,那到这个方法后干啥呢?调用
postToSubscription(),这个方法还熟悉吗?前面粘性事件Sticky中提到过,就是用的它,是它是它就是它!
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case POSTING: invokeSubscriber(subscription, event); break; case MAIN: if (isMainThread) { // 如果post()在主线程,则立即反射调用订阅方法 invokeSubscriber(subscription, event); } else { // 否认,加入UI线程消息队列末尾 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) { // 如果post()的线程为UI线程,则在线程池中反射调用订阅方法 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); } }
switch语句根据订阅方法的时候,注解中指定线程,分别post事件,一个一个的讲下为啥这么区分,先看下都用到的方法invokeSubscriber(),
void invokeSubscriber(Subscription subscription, Object event) { try { subscription.subscriberMethod.method.invoke(subscription.subscriber, event); } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); } }
订阅方法的Method对象调用invoke(),是一种反射机制,参数中知道了订阅者对象,订阅者方法的事件参数对象,那么就可以直接调用到这个订阅方法了,也就达到发送事件接受到事件的循环了。
POSTING
未指定订阅方法线程的时候默认值,直接调用,post在哪个线程,这个订阅方法就在哪个线程
MAIN
指定订阅方法在UI线程中执行,如果当前为UI线程直接调用,否则利用MainThreadSupport对象加入UI线程消息队列 末尾执行,MainThreadSupport其实就是主线程的Handler对象,后面再讲
MAIN_ORDERED
这个和MAIN有啥区别呢?其实区别就是如果MainThreadSupport存在会优先加入UI线程消息队列末尾,否则才是立即执行
BACKGROUND
如果当前为主线程,加入后台线程执行,否则立即执行
ASYNC
不管当前什么线程,都在后台执行
post主干逻辑基本都说完了,再说下刚才那几个poster,MainThreadSupport、BackgroundPoster、AsyncPoster
他们都是接口,继承于Poster。
MainThreadSupport
public class HandlerPoster extends Handler implements Poster { private final PendingPostQueue queue; private final int maxMillisInsideHandleMessage; private final EventBus eventBus; private boolean handlerActive; protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) { super(looper); this.eventBus = eventBus; this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; // 创建一个自定义的队列 queue = new PendingPostQueue(); } public void enqueue(Subscription subscription, Object event) { // 获取存储pendingPost list中最末一个 PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized (this) { // 获取到的pendingPost 入队 queue.enqueue(pendingPost); // 当前handler对象是否还活动,如果没有活动就让它活动起来,这里的代码就相当于启动handler的作用 // 让handler处于发送、接受消息的循环中 if (!handlerActive) { handlerActive = true; // 发送空消息,在消息队列末尾,就会执行下面的handleMessage(),如果发送消息未成功,抛出异常 if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); } } } } @Override public void handleMessage(Message msg) { boolean rescheduled = false; try { // 获取手机开机到现在的时间(毫秒),不包含睡眠时间 long started = SystemClock.uptimeMillis(); // 开启一个循环 while (true) { // 获取队列头部的pendingPost PendingPost pendingPost = queue.poll(); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized // 继续获取剩下队列头部的pendingPost pendingPost = queue.poll(); if (pendingPost == null) { // 如果获取了两次都是null,那么handlerActive = false;跳出方法 handlerActive = false; return; } } } // 通过反射调用订阅者对象的订阅方法 eventBus.invokeSubscriber(pendingPost); // 计算反射调用这个订阅方法的执行耗费时间(毫秒) long timeInMethod = SystemClock.uptimeMillis() - started; // 默认最大调用时间间隔是10毫秒,如果小于就继续循环从队列中取订阅方法反射调用, // 如果大于就把剩下需要调用的加入消息队列末尾,然后又来执行handleMessage(), // 因为这是在UI线程中进行的,如果调用时间过长,很容易出现ANR,所以把剩下没 // 调用完的加入消息队列末尾,让UI的其他操作先执行,防止阻塞 if (timeInMethod >= maxMillisInsideHandleMessage) { if (!sendMessage(obtainMessage())) { throw new EventBusException("Could not send handler message"); } // 因为已经加入了队列末尾,所有这个方法没有作用了可以退出去了 rescheduled = true; return; } } } finally { handlerActive = rescheduled; } } }
作用就是把post加入到UI线程消息队列末尾执行
BackgroundPoster
final class BackgroundPoster implements Runnable, Poster { private final PendingPostQueue queue; private final EventBus eventBus; private volatile boolean executorRunning; BackgroundPoster(EventBus eventBus) { this.eventBus = eventBus; queue = new PendingPostQueue(); } public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); synchronized (this) { queue.enqueue(pendingPost); // 线程池是否活跃中,如果没有,则开启 if (!executorRunning) { executorRunning = true; // 把当前BackgroundPoster对象放入线程池中并执行 eventBus.getExecutorService().execute(this); } } } @Override public void run() { try { try { while (true) { // 从PendingPostQueue中取头部PendingPost,如果取两次都为null,退出方法 PendingPost pendingPost = queue.poll(1000); if (pendingPost == null) { synchronized (this) { // Check again, this time in synchronized pendingPost = queue.poll(); if (pendingPost == null) { executorRunning = false; return; } } } // 利用反射调用订阅方法 eventBus.invokeSubscriber(pendingPost); } } catch (InterruptedException e) { eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e); } } finally { executorRunning = false; } } }
创建了一个线程池,然后在后台中执行
AsyncPoster
class AsyncPoster implements Runnable, Poster { private final PendingPostQueue queue; private final EventBus eventBus; AsyncPoster(EventBus eventBus) { this.eventBus = eventBus; queue = new PendingPostQueue(); } public void enqueue(Subscription subscription, Object event) { PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event); queue.enqueue(pendingPost); eventBus.getExecutorService().execute(this); } @Override public void run() { PendingPost pendingPost = queue.poll(); if(pendingPost == null) { throw new IllegalStateException("No pending post available"); } eventBus.invokeSubscriber(pendingPost); } }
跟BackgroundPoster相似
接下来看下注销事件
我们安卓中一般都会在Activity或者Fragment注册事件,如果不注销肯定会发生内存泄漏,导致内存溢出,
unregister()
/** * 储存事件及对应方法; * key是事件的Class对象,value是订阅者及订阅的方法集合 */ private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; /** * 储存订阅者及事件Class对象; * 用于判断订阅者是否注册过 */ private final Map<Object, List<Class<?>>> typesBySubscriber;
/** Unregisters the given subscriber from all event classes. */ public synchronized void unregister(Object subscriber) { List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class<?> eventType : subscribedTypes) { unsubscribeByEventType(subscriber, eventType); } typesBySubscriber.remove(subscriber); } else { logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } }
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */ private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { List<Subscription> subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { int size = subscriptions.size(); for (int i = 0; i < size; i++) { Subscription subscription = subscriptions.get(i); if (subscription.subscriber == subscriber) { subscription.active = false; subscriptions.remove(i); i--; size--; } } } }
其实我都不用解析了,还记得开始我提到过EventBus有几个成员变量,都是容器类,typesBySubscriber用于判断是否注册过,
subscriptionsByEventType这个很多地方都出现过,保存事件及对应订阅方法的,注销其实就是把这个订阅者和相关方法移除掉,
哈哈,是不是想到判断当前是否注册过的那个方法了,看下源码
public synchronized boolean isRegistered(Object subscriber) { return typesBySubscriber.containsKey(subscriber); }
明白了吧!
到这里EventBus这个优秀的框架主干都解析完了,我可能很多地方没描述清楚,不过小伙伴们懂逻辑原理就行了,细微的方法可以下面慢慢看下了。
EventBus说白了就是根据注解把相关的方法都保存在一个HashMap里面,key为事件Class对象,value为订阅者及相关订阅方法的集合,发送事件的时候就根据这个事件的Class对象从HashMap中拿出来一个一个循环的反射调用订阅者的订阅方法。
好了,又可以愉快玩耍了
相关文章推荐
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- android EventBus源码解析
- Android EventBus实战及源码解析 (一)
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- Android之EventBus概述及源码解析(雷惊风)
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus
- Android 之 EventBus 源码解析(精)
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus(二)
- Android EventBus源码解析 带你深入理解EventBus
- Android EventBus源码解析 带你深入理解EventBus