EventBus 是一款针对 Android 优化的发布/订阅事件总线
一、使用方法
1、EventBus 的三要素:
2、代码示例
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EventBus.getDefault().register(this); } @Subscribe(threadMode = ThreadMode.MAIN) public void onSubscribeEvent(MessageEvent messageEvent) { Log.i(TAG, "onSubscribeEvent: " + messageEvent.getMessage()); } @Override protected void onDestroy() { EventBus.getDefault().unregister(this); super.onDestroy(); } }
EventBus.getDefault().post(new MessageEvent("hello wshunli"));
|
3、EventBus 的 ThreadMode(线程模型)
- POSTING、和发送同一线程
- MAIN、主线程
- MAIN_ORDERED、主线程顺序执行
- BACKGROUND、非主线程;如果主线程发出,在子线程执行,如果子线程发出,在相同线程执行
- ASYNC、无论从什么线程发出,总是在
新建子线程执行
4、粘性事件(先发送,后注册接收)
EventBus.getDefault().postSticky(new MessageEvent("粘性事件")); @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) public void onSubscribeStickyEvent(MessageEvent messageEvent) { Log.i(TAG, "onSubscribeStickyEvent: " + messageEvent.getMessage()); }
|
implementation 'org.greenrobot:eventbus:3.2.0'
|
二、源码分析
2.1、EventBus 构造
public class EventBus { static volatile EventBus defaultInstance; private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder(); public static EventBus getDefault() { EventBus instance = defaultInstance; if (instance == null) { synchronized (EventBus.class) { instance = EventBus.defaultInstance; if (instance == null) { instance = EventBus.defaultInstance = new EventBus(); } } } return instance; } public EventBus() { this(DEFAULT_BUILDER); } EventBus(EventBusBuilder builder) { } }
|
EventBus 对象之间,订阅方法是隔离的,一般使用 getDefault()即可。
2.2、注册订阅
private final SubscriberMethodFinder subscriberMethodFinder; public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
|
(1)查找订阅方法
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>(); private List<SubscriberInfoIndex> subscriberInfoIndexes; 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; } }
|
Eventbus 支持 通过在编译期创建索引(SubscriberInfoIndex)以提高程序运行性能
https://greenrobot.org/eventbus/documentation/subscriber-index/
EventBus.builder().addIndex(new MySubscriberInfoIndex()).installDefaultEventBus();
List<SubscriberInfoIndex> subscriberInfoIndexes; public EventBusBuilder addIndex(SubscriberInfoIndex index) { if (subscriberInfoIndexes == null) { subscriberInfoIndexes = new ArrayList<>(); } subscriberInfoIndexes.add(index); return this; }
EventBus(EventBusBuilder builder) { subscriberMethodFinder = new SubscriberMethodFinder( builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex); }
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); } private SubscriberInfo getSubscriberInfo(FindState findState) { if (subscriberInfoIndexes != null) { for (SubscriberInfoIndex index : subscriberInfoIndexes) { SubscriberInfo info = index.getSubscriberInfo(findState.clazz); if (info != null) { return info; } } } return null; }
|
反射方式比较简单,不再粘贴代码。
(2)订阅方法注册
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(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); if (subscriberMethod.sticky) { if (eventInheritance) { 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); } } }
|
2.3、事件的发送、处理
(1)普通事件
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } };
final static class PostingThreadState { final List<Object> eventQueue = new ArrayList<>(); boolean isPosting; boolean isMainThread; Subscription subscription; Object event; boolean canceled; }
public void post(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); 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 { subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); } private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; synchronized (this) { subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { for (Subscription subscription : subscriptions) { postingState.event = event; postingState.subscription = subscription; boolean aborted; 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; } 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 { 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); } }
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); } }
|
(2)粘性事件
public void postSticky(Object event) { synchronized (stickyEvents) { stickyEvents.put(event.getClass(), event); } post(event); }
|
粘性事件仅将事件存入 stickyEvents 对象,真正调用在注册方法
if (subscriberMethod.sticky) { if (eventInheritance) { 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) { postToSubscription(newSubscription, stickyEvent, isMainThread()); } }
|
2.4、注销订阅
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()); } }
|
将订阅者、订阅方法从列表中移除
三、总结
优点,组件间通信解耦,预编译生成效率较高
缺点,代码可读性变差,逻辑分散
源码解析: