BroadcastReceiver
? 本質上是一個監聽器,分為接收者和發送者。用于監聽(接收)應用發出的廣播消息,并做出響應。可用于進程間通信、線程間通信和監聽系統的特定時間(如:電話呼入,網絡狀態變更等)。
使用觀察者模式:基于消息的發布/訂閱事件模型。
常用做與android 系統事件的監聽和交互。
消耗時間、空間較多,在onRecieve()方法內可以獲得Context和Intent參數,通過這兩個方法,可以調用AndroidSDK中的很多方法,屬于重量級組件。
可跨進程通信。
Eventbus
? 針對android跨進程、線程通信的優化方案,一定程度上可以代替廣播、handler、Intent。
優點
- 調度靈活,不依賴于context。
- 可繼承。
- 有事件優先級。
- 粘性事件機制。
- 量級較輕。
1. 實現原理
-
getDefault():通過懶漢單例模式獲取到對象
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
在new對象時,使用builder模式:
EventBus(EventBusBuilder builder) { subscriptionsByEventType = new HashMap<>(); typesBySubscriber = new HashMap<>(); stickyEvents = new ConcurrentHashMap<>(); mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); 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; }
-
register()實現如下:
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//通過反射的方式獲取到所有通過注解注冊的回調方法 synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod);//這里是具體的注冊方法 } } }
Subscribe():
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType;//獲取觸發本次消費的事件類型 Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//創建訂閱對象(把注冊者和事件消費方法綁定) CopyOnWriteArrayList<Subscription> 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<Class<?>> 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<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); } } }
以上就是EventBus注冊時的邏輯,接下來我們看看發布事件的時候的邏輯:
-
post():
public void post(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); List<Object> eventQueue = postingState.eventQueue;//獲取當前線程的消息隊列 eventQueue.add(event);//將本事件添加進消息隊列中 if (!postingState.isPosting) {//若當前 postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { while (!eventQueue.isEmpty()) {//循環遍歷事件隊列(在這兒可以類比handler機制不過不是死循環,也不存在阻塞,每post一次就進行判斷,是否處于posting) postSingleEvent(eventQueue.remove(0), postingState);//主要的消費邏輯 } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } }
這個currentPostingThreadState是做什么的呢,我們可以看一下它的聲明和實現:
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } };
這里使用了ThreadLocal,說明在每個線程里都會有這個對象的副本。我們接著往下看PostingThreadState是維護什么的類:
final static class PostingThreadState { final List<Object> eventQueue = new ArrayList<Object>();//事件隊列,用一個list維護 boolean isPosting;//是否在發布事件(就是之后的循環遍歷是否在執行) boolean isMainThread;//是否為主線程,通過判斷當前looper是否為MainLooper Subscription subscription;//當前的訂閱類,上面有說明 Object event;//當前正在處理的事件 boolean canceled;//當前事件是否被取消 }
我們繼續看postSingleEvent()方法,這里是事件消費的主要邏輯:
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 (logNoSubscriberMessages) { Log.d(TAG, "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<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 = 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; }
我們接著看:
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 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); } }
我們從默認的POSTING模式往下看:
void invokeSubscriber(PendingPost pendingPost) { Object event = pendingPost.event; Subscription subscription = pendingPost.subscription; PendingPost.releasePendingPost(pendingPost); if (subscription.active) { invokeSubscriber(subscription, event); } }
我們接著看:
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); } }
這樣我們可以知道,最后調用方法是通過反射來調用與之對應的消費事件的方法。