Android 框架煉成 教你如何寫元件間通訊框架EventBus

發表於2015-05-26

1、概述

關於Eventbus的介紹,前面已經有兩篇:Android EventBus實戰 沒聽過你就out了Android EventBus原始碼解析 帶你深入理解EventBus , 如果你覺得還有問題,沒關係,接下來我帶大家手把手打造從無到有的編寫這樣的框架~~~

首先我們回顧一下,這玩意就是在register時,掃描類中複合命名規範的方法,存到一個map,然後post的時候,查詢到匹配的方法,反射呼叫;好,那麼根據這一句話,我們就開始編寫框架之旅~~~

2、依然是原來的配方

以下出現的例項程式碼和Android EventBus實戰 沒聽過你就out了基本一致,所以我就貼出部分

1、ItemListFragment

2、ItemDetailFragment

可以看到,我們在ItemListFragment裡面使用了:

EventBus.getInstatnce().post(new ItemListEvent(Item.ITEMS));去釋出了一個事件,然後更新了我們的列表;

點選Item的時候,使用EventBus.getInstatnce().post(getListView().getItemAtPosition(position));釋出了一個事件,更新了我們的ItemDetailFragment的列表;

效果:

效果圖和之前的一摸一樣~~~

但是請注意,現在我們用的是EventBus.getInstatnce();併發是EventBus.getDefault();並且看下包名import com.zhy.eventbus.EventBus;

我想你應該明白了,這是我們自己寫的類來實現的~~~~

好了,接下來就帶大家一起實現這個類~~

ps :以上程式碼和效果圖,完全是為了部落格的完整性,勿見怪~~

3、無中生有

1、getInstance

我們這裡為了方便,直接簡單粗暴的使用惡漢模式建立單例:

然後在構造方法中初始化了一個mHandler,沒錯,它就是用來在處理在UI執行緒呼叫方法的。

接下來看register

2、register

可以看到我們使用了一個Map儲存所有的方法,key為引數的型別class;value為CopyOnWriteArrayList<SubscribeMethod>

這裡我們封裝了一個SubscribeMethod,這個裡面儲存了我們需要執行方法的所有引數,畢竟我們執行時,需要該方法,該方法所在的物件,以及在什麼執行緒執行;三個物件足以,當然也缺一不可了~~

register裡面,我們遍歷該類的所有方法,找到onEvent開頭的,封裝成SubscribeMethod,存在Map裡面,當然了,一個引數型別對應很多方法,所以value是個CopyOnWriteArrayList。

掃描完成,我們就完成了將方法的儲存。

還有一點,我們這裡預設在UI執行緒執行,如果方法是onEventAsync則認為在子執行緒執行,我們也只支援這兩種模式,簡化一點~

3、post

我們這裡學習了原始碼,也搞了個當前執行緒中的變數,儲存了一個事件佇列以及事件的狀態;

最終釋出的事件先加入到事件佇列,然後再取出來呼叫postEvent

postEvent也很簡單,直接根據引數型別,去map改到該方法,根據其threadMode,如果在UI執行緒,則判斷當前執行緒,如果是UI執行緒,直接呼叫,否則通過handler執行;

如果非UI執行緒,這裡我們直接開啟了一個Thread去執行;

invokeMethod很簡單,就是反射呼叫方法了~

4、unregister

unregister時,由於我們沒有存任何的輔助狀態,我們只能再去遍歷了方法了~~不過通過這個,也能反應出EventBus內部好幾個Map的作用了~~

並且,我們也不支援一些狀態的查詢,還是因為我們沒有存一些輔助狀態,例如isRegister等等。

到此,我們的EventBus就寫好了,100多行程式碼,肯定沒有EventBus健壯,主要目的還是學習人家的思想,經過自己寫了這麼個類,我相信對於EventBus的理解就更深刻了~面試的時候,恨不得拿只筆寫給面試官看,哈哈~~

5、EventBus最佳實踐

前面的文章,很多朋友問,如果我多個方法引數都一樣,豈不是post一個此引數,會多個方法呼叫;而此時我想呼叫指定的方法怎麼辦?

還有,專案中會有很多地方去接收List引數,而List<T>中的泛型是不一致的,所以也可能post(List)時,會呼叫很多方法,造成出錯。

的確,上述,不加處理肯定會出現;

但是,推薦大家在使用EventBus的時候,建立一個事件類,把你的每一個引數(或者可能發生衝突的引數),封裝成一個類:

例如:

這樣的話,就不會發生什麼呼叫衝突了~~

原始碼點選下載

相關文章