EventBus是針一款對Android的發佈/訂閱事件總線。它可以讓我們很輕鬆的實現在Android各個組件之間傳遞消息,並且代碼的可讀性更好,耦合度更低。
優點
代碼的簡潔性
不依賴於context
可以指定處理事件的線程,線程切換很方便
父類對通知的監聽與處理可繼承給子類
通知的優先級
黏性事件,可以在事件訂閱前發送
缺點:
對代碼邏輯分析增加難度
觀察者可能會造成接口的膨脹
不支持跨進程
BroadcastReceiver
與android系統進行相關的通知,還是要選擇本地廣播
需要使用Context和intent等對象
本地廣播是相對消耗時間、空間最多的一種方式
可以跨進程
一.基本使用
1.Gradle文件中導入
implementation 'org.greenrobot:eventbus:3.1.1'
2.在需要訂閱事件的地方註冊事件
EventBus.getDefault().register(this);
3.發送事件
public class MessageEvent {
String message;
}
//發送普通事件
EventBus.getDefault().post(messageEvent);
//發送黏性事件
EventBus.getDefault().postSticky(messageEvent)
4.接收並處理事件
@Subscribe(threadMode = ThreadMode.PostThread)
public void onEvent(MessageEvent messageEvent) {
...
}
5.取消訂閱
EventBus.getDefault().unregister(this);
在3.0之前,EventBus還沒有使用註解方式。消息處理的方法也只能限定於onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,分別代表四種線程模型。而在3.0之後,消息處理的方法可以隨便取名,但是需要添加一個註解@Subscribe,並且要指定線程模型(默認爲PostThread),注意,事件處理函數的訪問權限必須爲public,否則會報異常。
在EventBus中的觀察者通常有四種線程模型,分別是PostThread(默認)、MainThread、BackgroundThread與Async。
PostThread:如果使用事件處理函數指定了線程模型爲PostThread,那麼該事件在哪個線程發佈出來的,事件處理函數就會在這個線程中運行,也就是說發佈事件和接收事件在同一個線程。
MainThread:如果使用事件處理函數指定了線程模型爲MainThread,那麼不論事件是在哪個線程中發佈出來的,該事件處理函數都會在UI線程中執行。
BackgroundThread:如果使用事件處理函數指定了線程模型爲BackgroundThread,那麼如果事件是在UI線程中發佈出來的,那麼該事件處理函數就會在新的線程中運行,如果事件本來就是子線程中發佈出來的,那麼該事件處理函數直接在發佈事件的線程中執行。
Async:如果使用事件處理函數指定了線程模型爲Async,那麼無論事件在哪個線程發佈,該事件處理函數都會在新建的子線程中執行。
EventBus還支持發送黏性事件。簡單講,就是在發送事件之後再訂閱該事件也能收到該事件,跟黏性廣播類似。
發送黏性事件EventBus.getDefault().postSticky(new MessageEvent(“test”));
二.實現原理
從EventBus的註冊說起
//獲取EventBus的實例 單例模式
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;
}
1.EventBus的register()方法
public void register(Object subscriber) {
//獲取訂閱事件的類的class
Class<?> subscriberClass = subscriber.getClass();
//找到該類所有訂閱事件的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
//遍歷訂閱的方法
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// 對訂閱方法進行註冊
subscribe(subscriber, subscriberMethod);
}
}
}
SubscriberMethodFinder的findSubscriberMethods()方法
//METHOD_CACHE 爲存儲着訂閱事件的類 以及它對應的所有訂閱事件的方法
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;
}
}
SubscriberMethodFinder的findUsingInfo()方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
// 這裏通過FindState對象來存儲找到的方法信息
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);
}
//獲取當前類的父類直到返回爲null則跳出循環,findState.clazz=clazz.getSuperclass()
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
SubscriberMethodFinder的findUsingReflectionInSingleClass()方法
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// 獲取該類中聲明的所有方法
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();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
//獲取方法的參數
Class<?>[] parameterTypes = method.getParameterTypes();
//檢查是否只有一個參數 只接收一個參數
if (parameterTypes.length == 1) {
//獲取方法的Subscribe註解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
//
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
//將方法相關信息(Method,參數類型,TheadMode,優先級,是否是黏性事件) 封裝到SubscriberMethod對象中
//再SubscriberMethod對象緩存到集合
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");
}
}
}
FindState相關類方法
static class FindState {
//緩存subscriberClass類對應訂閱方法的集合
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
boolean checkAdd(Method method, Class<?> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
.........................................................................................................................
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** 排除java和android系統包下的類 */
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
}
EventBus的subscribe()方法
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
//將訂閱類與訂閱的方法封裝到Subscription 對象中
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 嘗試從緩存中根據事件類型來獲取所有的Subscription對象
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);
}
}
}
2.EventBus的post()方法
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
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 {
// 循環eventQueue來發送事件 發送一個就將事件從隊列中移除一個
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
EventBus的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);
//最終執行postSingleEventForEventType()方法
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
//最終執行postSingleEventForEventType()方法
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));
}
}
}
EventBus的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;
}
接着調用EventBus的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 {
//實際上是調用了主線程的Hander的sendMessage()方法
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
if (mainThreadPoster != null) {
//mainThreadPoster繼承HanderPoster,HanderPoster繼承自Hander ,HanderPoster中的Looper爲主線程的Looper
//mainThreadPoster實際上是一個主線程的Handler對象,enqueue()方法最終調用sendMessage()方法
//接着調用handleMessage()方法 該方法中調用eventBus.invokeSubscriber()方法
//將事件切換到主線程
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
//backgroundPoster實現了Runnable接口
//獲取線程池對象並執行runnable任務,eventBus.getExecutorService().execute(this);
//接着在run()方法中調用eventBus.invokeSubscriber()方法
//切換到工作線程
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
//asyncPoster實現了Runnable接口
//獲取線程池對象並執行runnable任務,eventBus.getExecutorService().execute(this);
//接着在run()方法中調用eventBus.invokeSubscriber()方法
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
invokeSubscriber()方法通過反射實現
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);
}
}
線程的切換
首先看EventBusBuilder類
public class EventBusBuilder {
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
.......................................
ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
.......................................
//存儲着主線程的Looper
MainThreadSupport mainThreadSupport;
........................................
//可以自定義ExecutorService對象
public EventBusBuilder executorService(ExecutorService executorService) {
this.executorService = executorService;
return this;
}
MainThreadSupport getMainThreadSupport() {
if (mainThreadSupport != null) {
return mainThreadSupport;
} else if (AndroidLogger.isAndroidLogAvailable()) {
Object looperOrNull = getAndroidMainLooperOrNull();
return looperOrNull == null ? null :
new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
} else {
return null;
}
}
Object getAndroidMainLooperOrNull() {
try {
//獲取了主線程的Looper對象
return Looper.getMainLooper();
} catch (RuntimeException e) {
// Not really a functional Android (e.g. "Stub!" maven dependencies)
return null;
}
}
}
MainThreadSupport類保存着一個主線程的Looper對象
public interface MainThreadSupport {
boolean isMainThread();
Poster createPoster(EventBus eventBus);
class AndroidHandlerMainThreadSupport implements MainThreadSupport {
private final Looper looper;
public AndroidHandlerMainThreadSupport(Looper looper) {
this.looper = looper;
}
//判斷是否在主線程
@Override
public boolean isMainThread() {
return looper == Looper.myLooper();
}
@Override
public Poster createPoster(EventBus eventBus) {
//HandlerPoster extends Handler 這裏創建了一個主線程的Handler對象
return new HandlerPoster(eventBus, looper, 10);
}
}
}
HandlerPoster類
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 pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
//主線程發送消息
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 = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
//在主線程中調用訂閱方法
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
取消訂閱 (數據移除)將訂閱事件的類從Map中移除 清空訂閱事件的類相關訂閱方法和訂閱類型
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());
}
}