Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android事件總線 ( AndroidEventBus ) 框架發布

Android事件總線 ( AndroidEventBus ) 框架發布

編輯:關於Android編程

AndroidEventBus Logovc/C6beztcSjrL/JxNzO0sPHtdrSu8/rtb21xMrHyrnTw7njsqW908rVxvfAtNTay/zDx9auvOS9+NDQvbu7paGjwP3I58nPyvbL+cu11NpBY3Rpdml0eS1C1tC3otK7uPa547Klo6zU2kFjdGl2aXR5LUHW0NeisuHSu7j2ueOypb3TytXG98C0vdPK3LjDueOypaGjtavKudPDueOypb3TytXG98nUz9TC6bezo6zI57n7xOPSqr2r0ru49sq1zOXA4LWx1/bK/b7d1NrX6bz+1q685LSrtd2jrMTHw7S4w8q1zOXA4Lu5tcPKtc/W0PLB0LuvvdO/2qOs1eK49rPJsb7KtdTa09C147jfsKGjocjnz8LL+cq+IDogICAgICAgICA8L3A+CgoKCjxwcmUgY2xhc3M9"brush:java;"> // ActivityA中注冊廣播接收器 class ActivityA extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { User person = intent.getParcelableExtra("user") ; } }, new IntentFilter("my_action")) ; } // ...... } // ActivityB中發布廣播 class ActivityB extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = new Intent("my_action") ; intent.putExtra("user", new User("mr.simple")) ; sendBroadcast(intent); } // ...... } // 實體類實現序列化 class User implements Parcelable { String name ; public User(String aName) { name = aName ; } // 代碼省略 @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); } }

是不是有很麻煩的感覺!事件總線框架就是為了簡化這些操作,並且降低組件之間的耦合而出現的。
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的不同

greenrobot的EventBus是一個非常流行的開源庫,但是它在使用體驗上並不友好,例如它的訂閱函數必須以onEvent開頭,並且如果需要指定該函數運行的線程則又要根據規則將函數名加上執行線程的模式名,這麼說很難理解,比如我要將某個事件的接收函數執行在主線程,那麼函數名必須為onEventMainThread。那如果我一個訂閱者中有兩個參數名相同,且都執行在主線程的接收函數呢? 這個時候似乎它就沒法處理了。而且規定死了函數命名,那就不能很好的體現該函數的功能,也就是函數的自文檔性。AndroidEventBus使用注解來標識接收函數,這樣函數名不受限制,比如我可以把接收函數名寫成updateUserInfo(Person info),這樣就靈活得多了。 另一個不同就是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 注冊事件接收對象
public class YourActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
        // 注冊對象
        EventBus.getDefault().register(this);
    }

    @Override
    protected void onDestroy() {
        // 不要忘記注銷!!!!
        EventBus.getDefault().unregister(this);
        super.onDestroy();
    }
}
2 通過Subscriber注解來標識事件接收對象中的接收方法
public class YourActivity extends Activity {
    // code ......

    // 接收方法,默認的tag,執行在UI線程
    @Subcriber
    private void updateUser(User user) {
        Log.e("", "### update user name = " + user.name);
    }

    // 含有my_tag,當用戶post事件時,只有指定了"my_tag"的事件才會觸發該函數,執行在UI線程
    @Subcriber(tag = "my_tag")
    private void updateUserWithTag(User user) {
        Log.e("", "### update user with my_tag, name = " + user.name);
    }

    // 含有my_tag,當用戶post事件時,只有指定了"my_tag"的事件才會觸發該函數,
    // post函數在哪個線程執行,該函數就執行在哪個線程    
    @Subcriber(tag = "my_tag", mode=ThreadMode.POST)
    private void updateUserWithMode(User user) {
        Log.e("", "### update user with my_tag, name = " + user.name);
    }

    // 含有my_tag,當用戶post事件時,只有指定了"my_tag"的事件才會觸發該函數,執行在一個獨立的線程
    @Subcriber(tag = "my_tag", mode = ThreadMode.ASYNC)
    private void updateUserAsync(User user) {
        Log.e("", "### update user async , name = " + user.name + ", thread name = " + Thread.currentThread().getName());
    }
}

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

3 在其他組件,例如Activity, Fragment,Service中發布事件
    EventBus.getDefault().post(new User("android"));

    // post a event with tag, the tag is like broadcast's action
    EventBus.getDefault().post(new User("mr.simple"), "my_tag");

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

Github鏈接

歡迎star和fork, AndroidEventBus框架 。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved