Android 框架之EventBus(一)

EventBus 是一個Android端優(yōu)化的 publish/subscribe 消息總線,簡化了應用程序各個組件間(Activity,Service,Fragment等),組件和后臺線程間的通信. 比如網(wǎng)絡請求 , 等網(wǎng)絡返回時通過Handler 或者 Broadcast 通知 UI , Fragment之間的通信 等功能都可以通過EventBus 實現(xiàn).

EventBus-Publish-Subscribe.png

相關鏈接 :

EventBus 基本使用

  • 在 build.gradle 中添加依賴,同步項目.
compile 'org.greenrobot:eventbus:3.0.0'
  • 定義傳遞小的消息實體類, 這個類的內容可以自定義,比如我這里定義一個EventBusMsg類.
public class EventBusMsg {
    // 類的結構是自定義的,我這類添加了一個 String類型的 name 字段 方便測試.
    public String name;

    public EventBusMsg(String name) {
        this.name = name;
    }
}
  • 訂閱事件
    訂閱事件需要進行三步設置,注冊,解注冊和定義事件接收函數(shù),比如我在MainActivity中接收事件進行如下操作.

    • 在MainActivity 的onCreate()方法中注冊EventBus .
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          ...
          // 1. 注冊
          EventBus.getDefault().register(MainActivity.this);
      }
    
    • 在MainActivity 的onDestroy() 方法中 解注冊 EventBus . 一定不要忘記解注冊否則可能會造成內存泄漏.
      @Override
      protected void onDestroy() {
          super.onDestroy();
          // 2. 解注冊
          EventBus.getDefault().unregister(MainActivity.this);
      }
    
    • 定義事件接收方法,方法名稱自定義,使用注解@Subscribe()標示.
      @Subscribe(threadMode = ThreadMode.MAIN)
      public void onMessageEvent(EventBusMsg event) {
          Log.d(TAG, "接收到信息");
          tv_console.setText("EventBus 數(shù)據(jù) : " + event.name);
      }
    
    1. 使用 @Subscribe() 注解來表明這個方法是EventBus事件接收的方法.
    2. 事件接收方法的參數(shù)必須和EventBus發(fā)送的事件類是同一類型.比如我使用了自己定義的EventBusMsg類.
    3. 在 @Subscribe() 中可以設置threadMode 來設置不同的模式.關于threadMode下面會有講解,這里使用ThreadMode.MAIN表明這個方法運行在主線程中.
  • 發(fā)布事件
    發(fā)布事件比較簡單調用EventBus的post方法即可, 我這里在EventBusSendActivity中發(fā)布事件因此我在EventBusSendActivity的Button的點擊事件中添加如下代碼.

public void sendMsg(View view) {
    // 發(fā)送消息
    EventBus.getDefault().post(new EventBusMsg("我是EventBus發(fā)送的數(shù)據(jù)"));
    // 銷毀當前Activity
    finish();
}

到此我們就完成了EventBus的最基本使用 , 我在MainActivity中注冊了事件監(jiān)聽,然后跳轉到EventBusSendActivity 中發(fā)布事件,事件發(fā)布完成后銷毀EventBusSendActivity,此時跳轉到MainActivity中,使用一個TextView打印剛才發(fā)布的時間的name.
注意 : 上面這中用法一定要先訂閱事件在進行發(fā)布事件才可以接收到事件,當然也可以實現(xiàn)先發(fā)布在訂閱的模式,后面會介紹

EventBus 事件回調方法線程(Delivery Thread)

EventBus會處理事件接收線程的問題 , 比如可以將消息發(fā)送到另外一個線程中,比如 : 在 線程A 中發(fā)布事件. 事件傳遞到線程B中執(zhí)行. 這個功能主要用在處理更新UI的問題上,我們都知道在Android中只有在UI線程中才可以更新UI,否則會引發(fā)異常.但是一下耗時操作比如網(wǎng)絡請求等又必須在子線程中執(zhí)行, 此時 EventBus就可以幫助我們處理UI和后臺任務的同步問題 . 就好像Android自帶的Handler 和 Broadcast機制一樣.
EventBus有四種線程模式 , 可以通過@Subscribe()注解的threadMode參數(shù)進行指定.

  • ThreadMode : POSTING
    POSTING是 threadMode的默認參數(shù),如果不設置該參數(shù)就是POSTING模式. 在這種模式下接收事件的方法和發(fā)布消息的方法運行在同一個線程中.
    優(yōu)點 : 這種模式下開銷最小,因為不需要切換線程.
// 運行在發(fā)布消息的線程中 (default)
// ThreadMode 是可選設置
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
    log(event.message);
}
  • ThreadMode : MAIN
    在 MAIN 模式下事件接收方法將會運行在主線程中(有時也稱為UI線程). 如果發(fā)布事件的線程是主線程那么事件就會直接發(fā)布給訂閱者,不會進行線程切換, 也就相當于使用了POSTING模式.
    使用注意 : 在此模式不要在事件接收方法中進行耗時操作,防止UI線程阻塞
// 運行在 UI 線程中(主線程)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
textField.setText(event.message);
}
  • ThreadMode : BACKGROUND
    事件接收方法將會運行在一個后臺線程中,但是事件不可以并發(fā)執(zhí)行.
    • 如果發(fā)布事件本身就在后臺線程中,那么事件接收方法就運行在這個線程中,不在另外開啟新的線程.
    • 如果發(fā)布事件在主線程中,那么EventBus會開一個后臺線程(只有一個)然后在該線程中依次處理所有事件.
      使用注意 : 事件處理方法應當盡快返回,避免阻塞后臺線程.
// 運行在后臺線程中.
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){
    saveToDisk(event.message);
}
  • ThreadMode : ASYNC
    在ASYNC模式下事件接收方法總是運行在一個發(fā)布事件線程和主線程之外獨立的線程中,發(fā)布事件不必依賴訂閱事件處理結果. 因此此模式適合于在事件處理中有比較耗時的操作的情況.為了避免同一時間有過多的運行線程.EventBus使用線程池和事件處理完成通知來限制最大的線程并發(fā)數(shù).
// 運行在一個獨立的線程中.
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){
    backend.send(event.message);
}

EventBus 高級一點的用法 : 粘性事件(Stick Events)

在EventBus的基本使用中我們說過那種模式必須要先訂閱事件然后再發(fā)布事件. 這次我們來嘗試一下EventBus另一種用法 粘性事件,在這種模式允許先發(fā)布事件再訂閱事件 . EventBus會將粘性事件保存在內存中然后發(fā)送給訂閱者,訂閱者也可以主動查詢粘性事件.

  • 定義事件實體類
    同樣事件實體類是可以自定義的我這類定義了EventBusStickyMsg實體類.
public class EventBusStickyMsg {
    public String name;
    public EventBusStickyMsg(String name) {
        this.name = name;
    }
}
  • 發(fā)布粘性事件
    發(fā)布粘性事件使用 postSticky() 方法, 我在MainActivity中添加如下代碼.
public void sendStickyEvent(View view) {
    EventBus.getDefault().postSticky(new EventBusStickyMsg("我是Sticky消息"));
    // 啟動 EventBusSendActivity
    Intent intent = new Intent(MainActivity.this, EventBusSendActivity.class);
    MainActivity.this.startActivity(intent);
}
  • 訂閱粘性事件
    訂閱粘性事件和訂閱普通事件是一樣的.都需要進行EventBus的注冊,解注冊以及事件接收函數(shù)
    • 注冊
     public void getStickyMsg(View view) {
          // 注冊,注意不要進行多次注冊,否則程序可能崩潰.可以設置一個標志.
          EventBus.getDefault().register(EventBusSendActivity.this);
      }
    

注意 : 不要進行重復注冊,可能造成程序崩潰

  • 解注冊
  @Override
  protected void onDestroy() {
      super.onDestroy();
      // 移除所有的粘性事件.
      EventBus.getDefault().removeAllStickyEvents();
      // 解注冊
      EventBus.getDefault().unregister(EventBusSendActivity.this);
  }
  • 定義事件接收方法
  @Subscribe(sticky = true , threadMode = ThreadMode.MAIN)
  public void onStickyEvent(EventBusStickyMsg event) {
      tv_console.setText("Sticky 數(shù)據(jù) : " + event.name);
  }

粘性事件接收方法需要在@Subscribe()注解中添加sticky = true 參數(shù).

到此粘性事件的使用就完成了. 程序流程大概如下 :

  1. 在MainActivity中發(fā)布粘性事件.
  2. 在EventBusSendActivity中注冊事件.
  3. 在TextView上顯示事件.

上面我們使用的是訂閱方式獲取事件. 我們也可以手動獲取粘性事件,我們添加一個Button在點擊事件中添加如下代碼

public void getStickyMsgManually(View view) {
    // 手動獲取粘性事件
    EventBusStickyMsg msg = EventBus.getDefault().getStickyEvent(EventBusStickyMsg.class);
    if (msg != null) {
        tv_console.setText(tv_console.getText().toString() + msg.name);
        // 刪除事件
        EventBus.getDefault().removeStickyEvent(msg);
    }
}

我們首先使用getStickyEvent()方法獲取粘性事件 , 但是我們獲取了該粘性事件后 , EventBus并不會主動刪除該粘性事件,(訂閱方式也不會刪除), 所以我們主動調用了removeStickyEvent() 方法刪除粘性事件.

同時我們通過查看removeStickyEvent()方法返回值可以發(fā)現(xiàn) , 他會將刪除的事件返回,因此我們修改代碼如下.

public void getStickyMsgRemove(View view) {
    // 手動獲取粘性事件
    EventBusStickyMsg msg = EventBus.getDefault().removeStickyEvent(EventBusStickyMsg.class);
    if (msg != null) {
        tv_console.setText(tv_console.getText().toString() + msg.name);
    }
}

OK 到此關于EventBus的基本使用已經(jīng)介紹完畢,我們主要介紹了一下三點內容 :

  • EventBus普通事件的使用方法.
  • EvnetBus粘性事件的使用方法.
  • EventBus訂閱事件線程模式.

Demo 下載地址 : http://download.csdn.net/detail/qq_16188829/9766568

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容