EventBus 3.1.1基礎使用和原理解析
EventBus 3.1.1基礎使用和原理淺析
1、簡介
EventBus 是一個 Android 事件釋出/訂閱框架,通過解耦釋出者和訂閱者簡化 Android 事件傳遞。 本文基於EventBus 3.1.1進行事件釋出/訂閱的使用和原理解析。
2、基礎使用
①、新增依賴
compile 'org.greenrobot:eventbus:3.1.1'
②、註冊 以在Activity中為例:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
EventBus eb = EventBus.getDefault();
if (!eb.isRegistered(this)) {
eb.register(this);
}
}
③、反註冊 如果註冊了那麼一定要反註冊,否則會導致記憶體洩漏 以在Activity中為例:
@Override
protected void onDestroy() {
EventBus eb = EventBus.getDefault();
if (eb. isRegistered(this)) {
eb.unregister(this);
}
super.onDestroy();
}
④、新增接收方法
//@Subscribe 注入事件接收方法,如果一個activity或者fragment已經註冊了,那麼必須擁有至少一個事件接收方法
//threadMode = ThreadMode.MAIN 該方法的邏輯在主執行緒中執行,可更改為BackGround使邏輯在後臺執行緒執行
//onEvent 方法名,可隨意取,不同的activity中的方法名可以重複
//(Object Event) 唯一標示,假如此處寫(User user),那麼該方法只能接收User型別的訊息
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(Object event) {
//TODO 接收到訊息後的邏輯
}
⑤、傳送訊息
//這裡的event的引用型別,就是onEvent接收方法裡Object要明確指定的類
EventBus.getDefault().post(event);
3、原理淺析
①、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);
}
}
}
通過傳入類獲取class物件和subscriberMethods,這裡著重看一下findSubscriberMethodsf()方法
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;
}
}
這個方法中通過class物件獲取了該class裡所有的事件接收方法,並返回一個List,再來看一下SubscriberMethod這個類
public class SubscriberMethod {
final Method method;//Method物件,用於反射呼叫
final ThreadMode threadMode;//事件接收方法內邏輯執行在何種執行緒
final Class<?> eventType;//事件接收方法接受的形參引用型別
final int priority;//優先順序
}
在register方法中通過
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
將所有的SubscriberMethod封裝為Subscription物件存入subscriptionsByEventType這個Map集合中 ②、post方法
/** Posts the given event to the event bus. */
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;
}
}
}
可以看到該方法最終呼叫了這個方法來執行post
postSingleEvent(eventQueue.remove(0), postingState);
該方法通過呼叫來執行post
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 = 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;
}
可以看到,這個方法通過eventClass從subscriptionsByEventType中獲取了CopyOnWriteArrayList subscriptions集合,並通過迴圈的方式逐一呼叫postToSubscription方法來進行post,那麼在看看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);
}
}
這個方法中,發現了invokeSubscriber方法,那麼繼續往下看
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);
}
}
這裡就很明顯的可以看見,該方法使用Method物件利用反射直接呼叫訂閱方法,實現了事件訂閱。 ③、效能問題 從以上原理淺析可以得出一個結論 1> 每一次register,EventBus就會把同一個EventType的訂閱方法Method物件存入同一個List集合並放入Map中進行管理。 2> 每次post,都會通過EventType從Map中取出所有List,然後迴圈該List逐一呼叫反射方法進行訊息傳送。 3> 因為反射是比較耗費資源的,所以在定義事件的時候儘量避免無用的呼叫,也就是說盡量細化event。