簡單瞭解一下eventbus的工作情況,學學大神的思想,那麼在此篇文章之前呢,建議大家先要了解清楚何爲註解和反射,如果沒了解,可以先看看前一篇文章,有具體的介紹 Android 註解 (Annotation)
使用過eventbus的都知道,eventbus是一個Android事件發佈/訂閱輕量級框架, 它可以完美的在任何地方完成通信任務,那麼不廢話啦,按照 咱們在Android中的使用過程爲思路展開一個瞭解吧
一、我們是在需要接受事件的地方(例如activity、fragment) 註冊 eventbus事件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(...);
//註冊eventbus事件
EventBus.getDefault().register(this);
}
好啦,如上代碼,我們在activity的oncreate生命週期方法中註冊了eventbus事件,那麼來看一下 getDefault()、register()方法到底幹了點什麼
//第一部分,獲取單例(懶漢式,"懶得創建自己")
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
//第二部分,註冊給定的訂閱服務器以接收事件。訂閱者必須調用{unregister(Object)取消註冊(對象)}
public void register(Object subscriber) {
//1.首先通過反射獲取到當前類
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//2
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);//3
}
}
}
第一部分 EventBus.getDefault() 是一個懶漢式單例。
第二部分是註冊,1.首先通過當前object.getclass()反射方法獲取到當前 class對象; 2.然後通過 findSubscriberMethods 方法獲取到一個當前class對象的所有方法,並放在一個list集合中,List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); 該行代碼中就是就是維護了 一個 ConcurrentHashMap 對象 ; 3.接下來就是一個 synchronized 同步塊,把該類和該類的多個方法進行配對訂閱
二、發送提交和訂閱消費
提交事件到總線: EventBus.getDefault().post(object);
//將給定事件提交到事件總線
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get(); //1
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {//2
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()) {
postSingleEvent(eventQueue.remove(0), postingState);//3
}
} finally { //最終把狀態都還原了
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
//-------------------current Posting Thread State --------------------------
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
//------------------Posting Thread State------------------------
/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<Object>(); //消息集合
boolean isPosting; //是否有發送
boolean isMainThread; //是否是主線程
Subscription subscription; //訂閱關係
Object event; //具體發送的事件體
boolean canceled; //是否取消了
}
1. PostingThreadState postingState = currentPostingThreadState.get() 該方法其實就是ThreadLocal對象(線程副本,爲線程本身存儲變量等信息),而PostingThreadState就是線程副本內所存儲JavaBean對象 (在此可以看出,該bean對象並沒有get set封裝),從bean對象中獲取到消息集合,並把當前post所要提交的消息保存在該集合中;
2. 使用 isposting 來判斷是否發送過信息,然後進入下一步判斷當前發送post方法執行的線程是否是主線程,設置發送狀態,判斷消息是否有效,while遍歷
3. while在集合非空狀態下,會不斷遍歷 postSingleEvent 方法,不斷從集合中獲取消息體和副本中數據進行處理,那麼在往下查看有 postToSubscription(subscription, event, postingState.isMainThread) 這樣的方法,它主要就是獲取咱們標籤中的value,根據不同的value 在不同的線程做不同的操作
//常用的四個標籤
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING://當前線程執行
invokeSubscriber(subscription, event);
break;
case MAIN: //事件的消費會在UI線程。因此,不宜進行耗時操作,以免引起ANR
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND://背景線程,如果事件在UI線程產生,那麼事件的消費會在單獨的子線程中進行。否則,在同一個線程中消費。
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC://異步執行,不管是否在UI線程產生事件,都會在單獨的子線程中消費事件
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
//---------------------反射中的 方法執行---------------------------
void invokeSubscriber(Subscription subscription, Object event) {
try {
//通過反射獲取到要執行的方法 subscription.subscriber,該方法的參數就是 通過 post要提交的消息
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
三、註銷
EventBus.getDefault().unregister(this);
//每個待消費事件的class都會對應一個list集合
private final Map<Object, List<Class<?>>> typesBySubscriber;
//取消註冊
public synchronized void unregister(Object subscriber) {
//獲取該activity或fragment對應的註解類
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
// 遍歷所有的訂閱方法 ,並取消
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
在使用的時候只是簡單導入eventbus jar,我們調用的時候只要簡單的註冊和配置註解標籤即可,極大提供了開發效率,這就是提供框架的好處;另外重要的一點,就是學習文中的“註冊”與“註銷”的精神,程序做到了有始有終,在開闢了內存,在內存中完成業務,然後在view組件結束生命週期的時候把所佔的內存、操作都結束了 ;初次解讀,有問題的地方要指出,互相提高吧