Android(安卓)认识EventBus到原理解析
目录
一、添加gradle依赖
二、基础操作
1、EventBus.getDefault();
2、EventBus.getDefault().register(this);
3、EventBus.getDefault().post(object);
4、EventBus.getDefault().unregister();
二、四个onEvent方法
三、EventBus3.0
四、原理简述
定义
EventBus是一款在 Android 开发中使用的发布、订阅事件总线框架,基于观察者模式,将事件的接收者和发送者分开,可以在Activity、Fragment、Service等组件交互通信,使用简单、效率高、体积小。
可以替代Intent、Broadcast、Thread+Handle异步线程间传递消息。
githup地址:https://github.com/greenrobot/EventBus
一、添加gradle依赖
implementation 'org.greenrobot:eventbus:3.1.1'
二、基础操作
1、EventBus.getDefault();
getDefault是一个单例方法,保证返回唯一的EventBus实例对象。
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
2、EventBus.getDefault().register(this);
public void register(Object subscriber) { // 反射获取当前注册类的Class对象 Class<?> subscriberClass = subscriber.getClass(); // 1、查找:根据Class查找当前类中订阅了事件的方法集合 List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { // 2、注册:循环遍历订阅了事件的方法集合,以完成注册 for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
主要分为查找和注册两部分,首先来看查找的过程,从
findSubscriberMethods()
开始:
List findSubscriberMethods(Class<?> subscriberClass) { // METHOD_CACHE是一个ConcurrentHashMap,直接保存了subscriberClass和对应SubscriberMethod的集合,以提高注册效率,赋值重复查找。 List subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } // 由于使用了默认的EventBusBuilder,则ignoreGeneratedIndex属性默认为false,即是否忽略注解生成器 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; } }
先从缓存中查找,如果找到则直接返回,否则去做下一步的查找过程,然后缓存查找到的集合,根据上边的注释可知
findUsingInfo()
方法会被调用:
private List findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); // 初始状态下findState.clazz就是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.clazz为subscriberClass的父类Class,即需要遍历父类 findState.moveToSuperclass(); } // 查找到的方法保存在了FindState实例的subscriberMethods集合中。 // 使用subscriberMethods构建一个新的List // 释放掉findState return getMethodsAndRelease(findState); }
findUsingInfo()
方法会在当前要注册的类以及其父类中查找订阅事件的方法,这里出现了一个FindState
类,它是SubscriberMethodFinder
的内部类,用来辅助查找订阅事件的方法,具体的查找过程在findUsingReflectionInSingleClass()
方法,它主要通过反射查找订阅事件的方法:
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类型,但非abstract、static等 if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { // 获得当前方法所有参数的类型 Class<?>[] parameterTypes = method.getParameterTypes(); // 如果当前方法只有一个参数 if (parameterTypes.length == 1) { Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); // 如果当前方法使用了Subscribe注解 if (subscribeAnnotation != null) { // 得到该参数的类型 Class<?> eventType = parameterTypes[0]; // checkAdd()方法用来判断FindState的anyMethodByEventType map是否已经添加过以当前eventType为key的键值对,没添加过则返回true if (findState.checkAdd(method, eventType)) { // 得到Subscribe注解的threadMode属性值,即线程模式 ThreadMode threadMode = subscribeAnnotation.threadMode(); // 创建一个SubscriberMethod对象,并添加到subscriberMethods集合 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)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } }
到此
register()
方法中findSubscriberMethods()
流程就分析完了,我们已经找到了当前注册类及其父类中订阅事件的方法的集合。接下来分析具体的注册流程,即register()
中的subscribe()
方法:
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { // 得到当前订阅了事件的方法的参数类型 Class<?> eventType = subscriberMethod.eventType; // Subscription类保存了要注册的类对象以及当前的subscriberMethod Subscription newSubscription = new Subscription(subscriber, subscriberMethod); // subscriptionsByEventType是一个HashMap,保存了以eventType为key,Subscription对象集合为value的键值对 // 先查找subscriptionsByEventType是否存在以当前eventType为key的值 CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); // 如果不存在,则创建一个subscriptions,并保存到subscriptionsByEventType 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); } } // 添加上边创建的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; } } // typesBySubscribere也是一个HashMap,保存了以当前要注册类的对象为key,注册类中订阅事件的方法的参数类型的集合为value的键值对 // 查找是否存在对应的参数类型集合 List> subscribedEvents = typesBySubscriber.get(subscriber); // 不存在则创建一个subscribedEvents,并保存到typesBySubscriber if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } // 保存当前订阅了事件的方法的参数类型 subscribedEvents.add(eventType); // 粘性事件相关的,后边具体分析 if (subscriberMethod.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). Set, Object>> entries = stickyEvents.entrySet(); for (Map.Entry, 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); } } }
这就是注册的核心流程,所以
subscribe()
方法主要是得到了subscriptionsByEventType
、typesBySubscriber
两个 HashMap。我们在发送事件的时候要用到subscriptionsByEventType
,完成事件的处理。当取消 EventBus 注册的时候要用到typesBySubscriber
、subscriptionsByEventType
,完成相关资源的释放。
3、EventBus.getDefault().post(object);
public void post(Object event) { //事件队列和线程模式等信息 PostingThreadState postingState = currentPostingThreadState.get(); List
post()
方法先将发送的事件保存的事件队列,然后通过循环出队列,将事件交给postSingleEvent()
方法处理:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; // eventInheritance默认为true,表示是否向上查找事件的父类 if (eventInheritance) { // 查找当前事件类型的Class,连同当前事件类型的Class保存到集合 List> eventTypes = lookupAllEventTypes(eventClass); int countTypes = eventTypes.size(); // 遍历Class集合,继续处理事件 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) { logger.log(Level.FINE, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } }
postSingleEvent()
方法中,根据eventInheritance
属性,决定是否向上遍历事件的父类型,然后用postSingleEventForEventType()
方法进一步处理事件:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList subscriptions; synchronized (this) { // 获取事件类型对应的Subscription集合 subscriptions = subscriptionsByEventType.get(eventClass); } // 如果已订阅了对应类型的事件 if (subscriptions != null && !subscriptions.isEmpty()) { for (Subscription subscription : subscriptions) { // 记录事件 postingState.event = event; // 记录对应的subscription 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; }
postSingleEventForEventType()
方法核心就是遍历发送的事件类型对应的Subscription集合,然后调用postToSubscription()
方法处理事件。
4、EventBus.getDefault().unregister();
public synchronized void unregister(Object subscriber) { // 得到当前注册类对象 对应的 订阅事件方法的参数类型 的集合 List> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { // 遍历参数类型集合,释放之前缓存的当前类中的Subscription for (Class<?> eventType : subscribedTypes) { unsubscribeByEventType(subscriber, eventType); } // 删除以subscriber为key的键值对 typesBySubscriber.remove(subscriber); } else { logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass()); } }private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { // 得到当前参数类型对应的Subscription集合 List subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { int size = subscriptions.size(); // 遍历Subscription集合 for (int i = 0; i < size; i++) { Subscription subscription = subscriptions.get(i); // 如果当前subscription对象对应的注册类对象 和 要取消注册的注册类对象相同,则删除当前subscription对象 if (subscription.subscriber == subscriber) { subscription.active = false; subscriptions.remove(i); i--; size--; } } } }
在
unregister()
方法中,释放了typesBySubscriber
、subscriptionsByEventType
中缓存的资源。
二、四个onEvent方法
- onEventMainThread
代表这个方法会在UI线程执行
- onEventPostThread
代表这个方法会在当前线程执行
- onEventBackgroundThread
代表非UI线程会在同线程执行,是的话在后台执行,一个一个调用。
- onEventAsync
代表加入后台任务,使用线程池调用,不是一个一个调用。
三、EventBus3.0
开始使用
Subscribe
注解配置事件订阅方法,可以指定threadMode
、sticky
、priority
三个属性。源码如下
@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface Subscribe { // 指定事件订阅方法的线程模式,即在那个线程执行事件订阅方法处理事件,默认为POSTING ThreadMode threadMode() default ThreadMode.POSTING; // 是否支持粘性事件,默认为false boolean sticky() default false; // 指定事件订阅方法的优先级,默认为0,如果多个事件订阅方法可以接收相同事件的,则优先级高的先接收到事件 int priority() default 0;}
其中,threadMode属性有如下几个可选值:
- ThreadMode.POSTING
默认的线程模式,在那个线程发送事件就在对应线程处理事件,避免了线程切换,效率高。
- ThreadMode.MAIN
如在主线程(UI线程)发送事件,则直接在主线程处理事件;如果在子线程发送事件,则先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
- ThreadMode.MAIN_ORDERED
无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
- ThreadMode.BACKGROUND
如果在主线程发送事件,则先将事件入队列,然后通过线程池依次处理事件;如果在子线程发送事件,则直接在发送事件的线程处理事件。
- ThreadMode.ASYNC
无论在那个线程发送事件,都将事件入队列,然后通过线程池处理。
四、原理简述
EventBus内部封装4个onEvent方法,然后post发送事件的时候,根据post参数类型自动匹配执行的方法。register(this)订阅在当前类,通过反射调用遍历当前类所有的方法,找到onEvent开发的方法,然后进行Map存储,key为class类型,值为对象实例。
更多相关文章
- Android(安卓)JVM的运行过程
- android开发之onCreate( )方法详解
- Android(安卓)桌面悬浮框
- android设置手机横屏与竖屏无效的解决方法
- Android(安卓)4.0源代码windows平台下载方法
- Retrofit2使用方式和源码解析
- Android-微信抢红包插件-原理分析
- android 常用混淆
- Android视图加载流程(2)之Window和WindowManager的创建与Activit