Android事件总线:EventBus
最近去维护另外一个项目,各种库使用的都比较老,eventbus使用的是2.x版本,于是来个升级,顺便读下eventbus的源码,在此做个笔记:
EventBus2.x升级3.x
2.x与3.x之间的对应关系:
onEvent--注解ThreadMode.POSTING;onEventMainThread--注解ThreadMode.MAINonEventAsync--注解ThreadMode.BACKGROUNDonEventBackgroundThread--注解ThreadMode.ASYNC
1.包名替换
Eventbus升级之后包名变了,可以ctrl+shift+r全局替换,也可以给studio设置自动导入包名将
import de.greenrobot.event.EventBus;替换成 import org.greenrobot.eventbus.EventBus; 全部替换.
2.方法需要使用注解方式
ctrl+shift+f 全局搜索, 依次添加上面提到的4个注解方法.
例如对onEvent方法,搜索"public void onEvent (" 添加"@Subscribe(threadMode = ThreadMode.POSTING)"
3.EventBus 3.0版本去掉了registerSticky, 换成到每个方法的注解中配置sticky = true. 搜索".registerSticky(", registerSticky替换回register, 再在该类下的方法注解上添加sticky.
EventBus源码解读:
1.EventBus的构造方法
/** 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;}
这里的单利模式用了双重检查模式,接下来看下EventBus的构造方法都做了什么:
...private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();...public EventBus() { this(DEFAULT_BUILDER);}
this调用了eventbus的另一个构造方法:
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;}
这里采用建造者模式,通过构造一个EventbusBuilder来对Eventbus进行配置
2.订阅注册
获取到Eventbus后,就可以将订阅者注册到Eventbus中,注册方法如下:
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); //查找订阅者(传进来的subscriber)的所有订阅方法的集合 List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { //遍历订阅者的方法,完成注册 for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } }}
1)查找订阅者的订阅方法
可以看到,注册方法做了两件事:①查找订阅者中所有订阅方法,②订阅者的注册。SubscriberMethod类主要用来保存订阅方法Method对象、线程模式(threadMode)、事件类型(eventType)、优先级(priority)、是否粘性事件(sticky)等。findSubscriberMethods如下:
List findSubscriberMethods(Class<?> subscriberClass) { //检查缓存中是否有 List subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } ``` //判断是否忽略注解器生成的MyEventBusIndex(参考http://greenrobot.org/eventbus/documentation/subscriber-index/) //默认false,可以通过EventbusBuilder来设置。因此我们使用通常使用的是findUsingInfo方法来获取订阅方法集合 ``` 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); while (findState.clazz != null) { //获取订阅者信息 findState.subscriberInfo = getSubscriberInfo(findState); //如果我们通过EventBuilder配置了MyEventBusIndex,便会获取到subscriberInfo if (findState.subscriberInfo != null) { SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); } } //没有通过EventBuilder配置MyEventBusIndex,调用此方法将订阅信息保存到findState,默认没有配置,走此方法 } else { findUsingReflectionInSingleClass(findState); } findState.moveToSuperclass(); } //对findState做回收处理,并返回订阅方法的集合 return getMethodsAndRelease(findState);}
more没有配置MyEventBusIndex,下面看下findUsingReflectionInSingleClass方法:
private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { //通过反射获取订阅者中的所有方法,这个方法比getMethods()快,特别是代码比较多的类如Activity methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { methods = findState.clazz.getMethods(); findState.skipSuperClasses = true; } for (Method method : methods) { //获取方法的修饰符,eg. public int modifiers = method.getModifiers(); if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1) { Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); if (subscribeAnnotation != null) { Class<?> eventType = parameterTypes[0]; if (findState.checkAdd(method, eventType)) { ThreadMode threadMode = subscribeAnnotation.threadMode(); //将订阅方法相关信息保存到findstate中 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"); } }}
至此,查找订阅者的订阅方法结束。
2)订阅者的注册过程
查找完订阅者的订阅方法之后,就开始对再所有订阅者方法进行注册,回到register方法中,看那里调用subscribe方法:
// Must be called in synchronized blockprivate void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { //订阅者订阅的方法的类型 Class<?> eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //根据eventType获取订阅对象集合,如果为空则重新创建 CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); 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> subscribedEvents = typesBySubscriber.get(subscriber); 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主要做了两件事,①将Subscription根据evntType封装到subscriptionsByEventType中,将subscribedEvents根据subscriber封装到typeBySubscriber中;②对粘性事件的处理。
3.事件发送
在获取到Eventbus对象之后,通过post方法,完成对事件的发送:
/** Posts the given event to the event bus. */public void post(Object event) { //PostingThreadState 保存着事件队列(eventQueue)和线程状态信息(isPosting,isMainThread,subscription,event,canceled) PostingThreadState postingState = currentPostingThreadState.get(); //获取事件队列,并将当前事件插入事件队列 List
看看postSingleEvent做了什么:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; //是否向上查找父类,默认true,可以通过EventBusBuilder配置 if (eventInheritance) { //查找所有注册事件 List> 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) { logger.log(Level.FINE, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } }}
通过postSingleEventForEventType方法对事件进行处理:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList subscriptions; synchronized (this) { //取出事件对应的订阅对象集合 subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { //将事件event和对应的Subscription(订阅对象)传递给postingState,通过调用postToSubscription方法对事件进行处理 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;}
看下postToSubscription做了什么:
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,如果提交的线程是主线程,则通过反射直接运行订阅的方法,若不是主线程,需要mainThreadPoster将我们的订阅事件添加到主线程队列中。mainThreadPoster继承自Handler,通过Handler将订阅方法切换到主线程。
至此,事件发送结束。
4.订阅者取消注册
取消注册是获取Eventbus对象之后,调用unregieter方法。
/** Unregisters the given subscriber from all event classes. */public synchronized void unregister(Object subscriber) { List> 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()); }}/** Unregisters the given subscriber from all event classes. */public synchronized void unregister(Object typesBySubscriber是一个map集合,在订阅的时候使用过。先通过subscriber找到subscribedTypes集合,然后将subscriber对应的eventTpye从typesBySubscriber中移除。遍历subscribedTypes并调用unsubscribeByEventType方法:/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { List 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--; } } }}
从subscriptions移除Subscriptions中移除,完成取消订阅。
参考资料:
1.https://www.jianshu.com/p/e28e1692d0c7
2.https://github.com/greenrobot/EventBus
3.《Android进阶之光》(刘望舒)第七章
更多相关文章
- Android-Service组件之AIDL
- Android(安卓)监听返回按钮事件
- Android(安卓)MediaScannerConnection,Android(安卓)MediaScanner
- Android(安卓)Web App官方文档翻译第四章:调试
- Android(安卓)8.1.0 SystemUI 修改之 - 系统锁屏状态下点击用户
- Android(安卓)5.1 启动有线网卡并为其分配静态IP地址
- Android注入事件的三种方法比较
- Android(安卓)JNI/NDK开发之基本姿势
- Android(安卓)实现ListView异步加载图片