AndroidEventBus,android事件總線框架

AndroidEventBus是一個Android平臺輕量級的事件總線框架, 它簡化了Activity、Fragment、Service等組件之間的交互,很大程度上降低了它們之間的耦合,使得我們的代碼更加簡潔,耦合性更低,提升我們的代碼質量。

在往下看之前,你可以考慮這麼一個場景,兩個Fragment之間的通信你會怎麼實現? 
按照Android官方給的建議的解決方法如下: Communicating with the Activity,思路就是Activity實現某個接口,然後在Fragment-A關聯上Activity之後將Activity強轉爲接口類型,然後在某個時刻Fragment中回調這個接口,然後再從Activity中調用Fragment-B中方法。這個過程是不是有點複雜呢? 如果你也這麼覺得,那也就是你繼續看下去的理由了

基本結構

結構圖

AndroidEventBus類似於觀察者模式,通過register函數將需要訂閱事件的對象註冊到事件總線中,然後根據@Subcriber註解來查找對象中的訂閱方法,並且將這些訂閱方法和訂閱對象存儲在map中。當用戶在某個地方發佈一個事件時,事件總線根據事件的參數類型和tag找到對應的訂閱者對象,最後執行訂閱者對象中的方法。這些訂閱方法會執行在用戶指定的線程模型中,比如mode=ThreadMode.ASYNC則表示該訂閱方法執行在子線程中,更多細節請看下面的說明。

與greenrobot和EventBus的區別

  1. greenrobot的EventBus是一個非常流行的開源庫,但是它在使用體驗上並不友好,例如它的訂閱函數必須以onEvent開頭,並且如果需要指定該函數運行的線程則又要根據規則將函數名加上執行線程的模式名,這麼說很難理解,比如我要將某個事件的接收函數執行在主線程,那麼函數名必須爲onEventMainThread。那如果我一個訂閱者中有兩個參數名相同,且都執行在主線程的接收函數呢? 這個時候似乎它就沒法處理了。而且規定死了函數命名,那就不能很好的體現該函數的功能,也就是函數的自文檔性。AndroidEventBus使用註解來標識接收函數,這樣函數名不受限制,比如我可以把接收函數名寫成updateUserInfo(Person info),這樣就靈活得多了。
  2. 另一個不同就是AndroidEventBus增加了一個額外的tag來標識每個接收函數可接收的事件的tag,這類似於Broadcast中的action,比如每個Broadcast對應一個或者多個action,當你發廣播時你得指定這個廣播的action,然後對應的廣播接收器才能收到.greenrobot的EventBus只是根據函數參數類型來標識這個函數是否可以接收某個事件,這樣導致只要是參數類型相同,任何的事件它都可以接收到,這樣的投遞原則就很侷限了。比如我有兩個事件,一個添加用戶的事件, 一個刪除用戶的事件,他們的參數類型都爲User,那麼greenrobot的EventBus大概是這樣的:
    private void onEventMainThread(User aUser) {
        // code 
    }

    如果你有兩個同參數類型的接收函數,並且都要執行在主線程,那如何命名呢 ? 即使你有兩個符合要求的函數吧,那麼我實際上是添加用戶的事件,但是由於EventBus只根據事件參數類型來判斷接收函數,因此會導致兩個函數都會被執行。AndroidEventBus的策略是爲每個事件添加一個tag,參數類型和tag共同標識一個事件的唯一性,這樣就確保了事件的精確投遞。 
    這就是AndroidEventBus和greenrobot的EventBus的不同,但是由於本人對greenrobot的EventBus並不是很瞭解,很可能上述我所說的有誤,如果是那樣,歡迎您指出。

    AndroidEventBus起初只是爲了學習,但是在學習了EventBus的實現之後,發現它在使用上有些不便之處,我想既然我有這些感覺,應該也是有同感之人,在開發羣裏交流之後,發現確實有這樣的情況。因此纔將正式地AndroidEventBus以開源庫的形式推出來,希望能夠幫助到一些需要的人。當然,這個庫的成長需要大家的支持與測試,歡迎大家發 pull request。

    如何使用AndroidEventBus

    你可以按照下面幾個步驟來使用AndroidEventBus.

    • 1 註冊事件接收對象
    <code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">YourActivity</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">Activity</span> {</span>
    
        <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">onCreate</span>(Bundle savedInstanceState) {
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">super</span>.onCreate(savedInstanceState);
            setContentView(R.layout.main_activity);
            <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// 註冊對象</span>
            EventBus.getDefault().register(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">this</span>);
        }
    
        <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">onDestroy</span>() {
            <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// 不要忘記註銷!!!!</span>
            EventBus.getDefault().unregister(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">this</span>);
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">super</span>.onDestroy();
        }
    }
    </code>
    • 2 通過Subscriber註解來標識事件接收對象中的接收方法
    <code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">YourActivity</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">Activity</span> {</span>
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// code ......</span>
    
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// 接收方法,默認的tag,執行在UI線程</span>
        <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Subcriber</span>
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">updateUser</span>(User user) {
            Log.e(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">""</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"### update user name = "</span> + user.name);
        }
    
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// 含有my_tag,當用戶post事件時,只有指定了"my_tag"的事件纔會觸發該函數,執行在UI線程</span>
        <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Subcriber</span>(tag = <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"my_tag"</span>)
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">updateUserWithTag</span>(User user) {
            Log.e(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">""</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"### update user with my_tag, name = "</span> + user.name);
        }
    
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// 含有my_tag,當用戶post事件時,只有指定了"my_tag"的事件纔會觸發該函數,</span>
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// post函數在哪個線程執行,該函數就執行在哪個線程    </span>
        <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Subcriber</span>(tag = <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"my_tag"</span>, mode=ThreadMode.POST)
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">updateUserWithMode</span>(User user) {
            Log.e(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">""</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"### update user with my_tag, name = "</span> + user.name);
        }
    
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// 含有my_tag,當用戶post事件時,只有指定了"my_tag"的事件纔會觸發該函數,執行在一個獨立的線程</span>
        <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Subcriber</span>(tag = <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"my_tag"</span>, mode = ThreadMode.ASYNC)
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">updateUserAsync</span>(User user) {
            Log.e(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">""</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"### update user async , name = "</span> + user.name + <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">", thread name = "</span> + Thread.currentThread().getName());
        }
    }</code>

    接收函數使用tag來標識可接收的事件類型,與BroadcastReceiver中指定action是一樣的,這樣可以精準的投遞消息。mode可以指定目標函數執行在哪個線程,默認會執行在UI線程,方便用戶更新UI。目標方法執行耗時操作時,可以設置mode爲ASYNC,使之執行在子線程中。

    • 3 在其他組件,例如Activity, Fragment,Service中發佈事件
    <code class=" hljs vhdl" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">    EventBus.getDefault().post(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> User(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"android"</span>));
    
        // post a event <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">with</span> tag, the tag <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">is</span> like broadcast<span class="hljs-attribute" style="box-sizing: border-box; color: rgb(136, 136, 255);">'s</span> action
        EventBus.getDefault().post(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> User(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"mr.simple"</span>), <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"my_tag"</span>);</code>

    發佈事件之後,註冊了該事件類型的對象就會接收到響應的事件.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章