玩轉EventBus,詳解其使用

image

概述

EventBus是一款針對Android優(yōu)化的發(fā)布/訂閱(publish/subscribe)事件總線抓半。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service狮惜,線程之間傳遞消息。簡化了應用程序內各組件間锻狗、組件與后臺線程間的通信祟同。優(yōu)點是開銷小,代碼更優(yōu)雅厢蒜。以及將發(fā)送者和接收者解耦霞势。比如請求網(wǎng)絡,等網(wǎng)絡返回時通過Handler或Broadcast通知UI斑鸦,兩個Fragment之間需要通過Listener通信愕贡,這些需求都可以通過EventBus實現(xiàn)。

EventBus作為一個消息總線巷屿,有三個主要的元素:

  • Event:事件固以。可以是任意類型的對象

  • Subscriber:事件訂閱者嘱巾,接收特定的事件憨琳。在EventBus中,使用約定來指定事件訂閱者以簡化使用旬昭。即所有事件訂閱都都是以onEvent開頭的函數(shù)篙螟,具體來說,函數(shù)的名字是onEvent问拘,onEventMainThread遍略,onEventBackgroundThread慢味,onEventAsync這四個,這個和 ThreadMode(下面講)有關墅冷。

  • Publisher:事件發(fā)布者纯路,用于通知 Subscriber 有事件發(fā)生∧蓿可以在任意線程任意位置發(fā)送事件驰唬,直接調用eventBus.post(Object) 方法,可以自己實例化 EventBus 對象腔彰,但一般使用默認的單例就好了:EventBus.getDefault()叫编, 根據(jù)post函數(shù)參數(shù)的類型,會自動調用訂閱相應類型事件的函數(shù)霹抛。

關于ThreadMode

前面說了搓逾,Subscriber的函數(shù)只能是那4個,因為每個事件訂閱函數(shù)都是和一個ThreadMode相關聯(lián)的杯拐,ThreadMode指定了會調用的函數(shù)霞篡。有以下四個ThreadMode:

  • PostThread:事件的處理在和事件的發(fā)送在相同的進程,所以事件處理時間不應太長端逼,不然影響事件的發(fā)送線程朗兵,而這個線程可能是UI線程。對應的函數(shù)名是onEvent顶滩。

  • MainThread: 事件的處理會在UI線程中執(zhí)行余掖。事件處理時間不能太長,這個不用說的礁鲁,長了會ANR的盐欺,對應的函數(shù)名是onEventMainThread。

  • BackgroundThread:事件的處理會在一個后臺線程中執(zhí)行仅醇,對應的函數(shù)名是onEventBackgroundThread冗美,雖然名字 是BackgroundThread,事件處理是在后臺線程着憨,但事件處理時間還是不應該太長墩衙,因為如果發(fā)送事件的線程是后臺線程务嫡,會直接執(zhí)行事件甲抖,如果當前線程是UI線程,事件會被加到一個隊列中心铃,由一個線程依次處理這些事件准谚,如果某個事件處理時間太長,會阻塞后面的事件的派發(fā)或處理去扣。

  • Async:事件處理會在單獨的線程中執(zhí)行柱衔,主要用于在后臺線程中執(zhí)行耗時操作樊破,每個事件會開啟一個線程(有線程池),但最好限制線程的數(shù)目唆铐。

根據(jù)事件訂閱都函數(shù)名稱的不同哲戚,會使用不同的ThreadMode,比如果在后臺線程加載了數(shù)據(jù)想在UI線程顯示艾岂,訂閱者只需把函數(shù)命名onEventMainThread顺少。

對相應的函數(shù)名,進一步解釋一下:

onEvent:如果使用onEvent作為訂閱函數(shù)王浴,那么該事件在哪個線程發(fā)布出來的脆炎,onEvent就會在這個線程中運行,也就是說發(fā)布事件和接收事件線程在同一個線程氓辣。使用這個方法時秒裕,在onEvent方法中不能執(zhí)行耗時操作,如果執(zhí)行耗時操作容易導致事件分發(fā)延遲钞啸。

onEventMainThread:如果使用onEventMainThread作為訂閱函數(shù)几蜻,那么不論事件是在哪個線程中發(fā)布出來的,onEventMainThread都會在UI線程中執(zhí)行体斩,接收事件就會在UI線程中運行入蛆,這個在Android中是非常有用的,因為在Android中只能在UI線程中跟新UI硕勿,所以在onEvnetMainThread方法中是不能執(zhí)行耗時操作的哨毁。

onEventBackground:如果使用onEventBackgrond作為訂閱函數(shù),那么如果事件是在UI線程中發(fā)布出來的源武,那么onEventBackground就會在子線程中運行扼褪,如果事件本來就是子線程中發(fā)布出來的,那么onEventBackground函數(shù)直接在該子線程中執(zhí)行粱栖。

onEventAsync:使用這個函數(shù)作為訂閱函數(shù)话浇,那么無論事件在哪個線程發(fā)布,都會創(chuàng)建新的子線程在執(zhí)行onEventAsync闹究。

基本用法

引入EventBus:

compile 'org.greenrobot:eventbus:3.0.0'

定義事件:

public class MessageEvent { /* Additional fields if needed */ }

注冊事件接收者:

eventBus.register(this);

發(fā)送事件:

eventBus.post(event)

接收消息并處理:

public void onEvent(MessageEvent event) {}

注銷事件接收:

eventBus.unregister(this);

最后幔崖,proguard 需要做一些額外處理:

#EventBus
 -keepclassmembers class ** {
    public void onEvent*(**);
    void onEvent*(**);
 }

實戰(zhàn)舉例

關于Activity之間的通信

第一步:自定義一個定義Event事件,用來封裝信息
例子如下:

public class UserEvent {

    private String userName;

    public UserEvent() {
    }

    public UserEvent(String userName) {
        this.userName = userName;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}

第二步:注冊訂閱者和定義處理方法

public class MainActivity extends Activity {
    private Button btn, fragment_btn;
    private TextView service_tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //注冊訂閱者
        EventBus.getDefault().register(this);
        btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent intent = new Intent(MainActivity.this,
                        SecondActivity.class);
                startActivity(intent);
            }
        });
        fragment_btn = (Button) findViewById(R.id.fragment_btn);
        fragment_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,
                        FragmenTestActivity.class);
                startActivity(intent);
            }
        });
        service_tv = (TextView) findViewById(R.id.service_tv);
        startService(new Intent(this, EventTestService.class));
    }

    //定義處理接收方法
    @Subscribe
    public void onEventMainThread(UserEvent event) {
        btn.setText(event.getUserName());
        service_tv.setText(event.getUserName());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

}

第三步:發(fā)送事件

public class SecondActivity extends Activity {
    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final UserEvent ue = new UserEvent();
                ue.setUserName("非著名程序員");
                EventBus.getDefault().post(ue);
                finish();
            }
        });
    }

}

fragment,service等之間的通信和activity之間的基本一樣渣淤,就不過多的貼代碼解釋了赏寇,感興趣的同學可以直接下載demo,里面有它們之間的通信价认。

使用EventBus應該注意以下幾點:

  1. 同一個onEvent函數(shù)不能被注冊兩次嗅定,所以不能在一個類中注冊同時還在父類中注冊。

  2. 消息的接收是根據(jù)參數(shù)中的類名來決定執(zhí)行哪一個接收處理方法的用踩。即:訂閱者的處理方法是根據(jù)訂閱事件的類型來確定訂閱函數(shù)的渠退。

  3. 每個事件可以有多個訂閱者忙迁。

  4. 當Post一個事件時,這個事件類的父類的事件也會被Post碎乃。

  5. 所有事件處理方法必需是public void類型的姊扔,并且只有一個參數(shù)表示EventType。

在這里我把demo分享出去梅誓,demo里包含了Activity之間的通信旱眯,fragment之間的通信和service與activity之間的通信。

小編有給大家準備安卓進階學習資料視頻证九,加群即可獲取
群號:4112676

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末删豺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子愧怜,更是在濱河造成了極大的恐慌呀页,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拥坛,死亡現(xiàn)場離奇詭異蓬蝶,居然都是意外死亡,警方通過查閱死者的電腦和手機猜惋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門丸氛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人著摔,你說我怎么就攤上這事缓窜。” “怎么了谍咆?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵禾锤,是天一觀的道長。 經常有香客問我摹察,道長恩掷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任供嚎,我火速辦了婚禮黄娘,結果婚禮上,老公的妹妹穿的比我還像新娘克滴。我一直安慰自己逼争,他們只是感情好,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布偿曙。 她就那樣靜靜地躺著氮凝,像睡著了一般羔巢。 火紅的嫁衣襯著肌膚如雪望忆。 梳的紋絲不亂的頭發(fā)上罩阵,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音启摄,去河邊找鬼稿壁。 笑死,一個胖子當著我的面吹牛歉备,可吹牛的內容都是我干的傅是。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼蕾羊,長吁一口氣:“原來是場噩夢啊……” “哼喧笔!你這毒婦竟也來了?” 一聲冷哼從身側響起龟再,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤书闸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后利凑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浆劲,經...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年哀澈,在試婚紗的時候發(fā)現(xiàn)自己被綠了牌借。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡割按,死狀恐怖膨报,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情适荣,我是刑警寧澤丙躏,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站束凑,受9級特大地震影響晒旅,放射性物質發(fā)生泄漏。R本人自食惡果不足惜汪诉,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一废恋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扒寄,春花似錦鱼鼓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至课竣,卻和暖如春嘉赎,著一層夾襖步出監(jiān)牢的瞬間置媳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工公条, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拇囊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓靶橱,卻偏偏與公主長得像寥袭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子关霸,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內容

  • 前言:EventBus出來已經有一段時間了传黄,github上面也有很多開源項目中使用了EventBus。所以抽空學習...
    Kerry202閱讀 1,286評論 1 2
  • 最近在項目中使用了EventBus(3.0)队寇,覺得非常好用尝江,于是就看了一些關于EventBus源碼分析的文章,現(xiàn)在...
    shenhuniurou閱讀 1,506評論 0 4
  • 先吐槽一下博客園的MarkDown編輯器英上,推出的時候還很高興博客園支持MarkDown了炭序,試用了下發(fā)現(xiàn)支持不完善就...
    Ten_Minutes閱讀 565評論 0 2
  • 概述 EventBus是一個Android事件發(fā)布/訂閱框架,通過解耦發(fā)布者和訂閱者簡化Android事件傳遞苍日,這...
    劉滌生閱讀 78,480評論 6 57
  • Android 淺析EventBus (一) 使用 前言 Linus Benedict Torvalds : RT...
    CodePlayer_Jz閱讀 3,105評論 3 10