EventBus使用詳解

前言

最近在公司做一個類似于手機工廠模式的一個項目锐峭,用來檢測其他各個App是否正常工作中鼠,所以要求是盡可能的輕量級可婶,因為是檢測其他App的工作,所以整個項目都是信息之間的頻繁交互援雇。在項目中存在很多Fragment和Fragment之間的信息交互矛渴,之前一直在用廣播來實現但是廣播使用起來較為麻煩且效率不高。在同事的建議下學習了EventBus惫搏,在此做一下學習記錄具温,侵權請告知一定及時刪除。

EventBus概述

EventBus是針一款對Android的發(fā)布/訂閱事件總線筐赔。它可以讓我們很輕松的實現在Android各個組件之間傳遞消息铣猩,并且代碼的可讀性更好,耦合度更低茴丰。

1.基本用法##

示例:

當擊StartSecondActivity按鈕的時候达皿,跳到第二個Activity,當點擊第二個activity上面的SendMessage按鈕的時候向第一個Activity發(fā)送消息贿肩,當第一個Activity收到消息后將消息放入textView中顯示峦椰。

屏幕快照 2017-09-16 13.26.22.png

屏幕快照 2017-09-16 13.27.04.png

屏幕快照 2017-09-16 13.27.17.png

用法:

(1)先定義一個類
public class MessageEvent {
        .......
}

(2)在需要接收消息的頁面注冊事件(類似于動態(tài)注冊廣播)
EventBus.getDefault().register(this);
(3)發(fā)送消息
EventBus.getDefault().post(new MessageEvent()); 
(4)處理消息( 在3.0之后,消息處理的方法可以隨便取名汰规,但是需要添加一個注解 @Subscribe汤功,并且要指定線程模型(默認為PostThread),四種線程模型溜哮,下面會講到滔金。)
@Subscribe(threadMode = ThreadMode.PostThread)
public void XXX(MessageEvent messageEvent) {
    ...
} 
(5)解除注冊( 類似于動態(tài)廣播的解除注冊)
EventBus.getDefault().post(new MessageEvent()); 

整體的流程就是這樣色解,注意:事件處理函數的訪問權限必須為public,否則會報異常餐茵。

示例代碼:

下面我將示例代碼描述一下:

(1)布局
MainActivity布局(activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.liuhe.eventbusdemo.MainActivity">

    <TextView
        android:id="@+id/show_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="25sp"
        android:text="Hello World" />

    <Button
        android:id="@+id/start_second"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start SecondActivity"/>

</LinearLayout>

新建一個SecondActivity(second.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="25sp"
        android:text="This is SecondaAtivity's message"/>

    <Button
        android:id="@+id/send"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send Message"/>

</LinearLayout>
(2)創(chuàng)建一個MessageEvent類
public class MessageEvent {

    private String message;

    public MessageEvent(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
    
}

這個類很簡單冒签,只需要我們在構造方法內傳入一個值,然后通過 getMessage()來獲取出來钟病。

(3)在要接收消息的界面注冊事件(別忘記在onDestory()中解除注冊)
EventBus.getDefault().register(MainActivity.this);
(4)處理消息
@Subscribe(threadMode = ThreadMode.POSTING)
    public void showMessageMainEvent(MessageEvent messageEvent){
        show_message.setText("Message from SecondActivity" + "---" +messageEvent.getMessage());
    }
(5)發(fā)送消息
 EventBus.getDefault().post(new MessageEvent(message));
完整代碼
(1)MainActivity
public class MainActivity extends AppCompatActivity {

    private TextView show_message;
    private Button start_second;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        show_message = (TextView) findViewById(R.id.show_message);
        start_second = (Button) findViewById(R.id.start_second);

        start_second.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });

        EventBus.getDefault().register(this);

    }


    @Subscribe(threadMode = ThreadMode.POSTING)
    public void showMessagePOSTINGEvent(MessageEvent messageEvent){
        show_message.setText("Message from SecondActivity" + "---" +messageEvent.getMessage());
    }

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

(2)SecondActivity
public class SecondActivity extends Activity{

    private Button button;
    private TextView textView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second);

        button = (Button) findViewById(R.id.send);
        textView = (TextView) findViewById(R.id.message);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String message = textView.getText().toString();
                if (TextUtils.isEmpty(message)){
                    message = "defaule message";
                }
                EventBus.getDefault().post(new MessageEvent(message));

            }
        });
    }
}

這就是基本的使用了萧恕,上文中我們使用的是POSTING線程模型,下面介紹一下EventBus的四種線程模型肠阱。

2.四種線程模型(ThreadMode)##

在寫消息處理的時候票唆,方法名字可以隨意命名,但是需要通過@Subscribe注解一下當前使用的線程模型屹徘。EventBus的縣城模型一共有四種:

  • POSTING(默認)
    如果使用事件處理函數指定了線程模型為PostThread走趋,那么該事件在哪個線程發(fā)布出來的,事件處理函數就會在這個線程中運行噪伊,也就是說發(fā)布事件和接收事件在同一個線程簿煌。在線程模型為PostThread的事件處理函數中盡量避免執(zhí)行耗時操作,因為它會阻塞事件的傳遞鉴吹,甚至有可能會引起ANR姨伟。
  • MAIN
    不論事件是在哪個線程中發(fā)布出來的,該事件處理函數都會在UI線程中執(zhí)行豆励。該方法可以用來更新UI夺荒,但是不能處理耗時操作。
  • BACKGROUND
    如果事件是在UI線程中發(fā)布出來的良蒸,那么該事件處理函數就會在新的線程中運行技扼,如果事件本來就是子線程中發(fā)布出來的,那么該事件處理函數直接在發(fā)布事件的線程中執(zhí)行嫩痰。在此事件處理函數中禁止進行UI更新操作剿吻。
  • ASYNC
    無論事件在哪個線程發(fā)布,該事件處理函數都會在新建的子線程中執(zhí)行串纺。同樣丽旅,此事件處理函數中禁止進行UI更新操作。

示例:

1.將上面的例子加上三個處理消息的方法造垛,分別指定為其余的三種線程模型魔招,我們現在UI線程線程發(fā)送一條消息看看Log打印結果。

(1)MainActivity代碼如下:
public class MainActivity extends AppCompatActivity {

    private TextView show_message;
    private Button start_second;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        show_message = (TextView) findViewById(R.id.show_message);
        start_second = (Button) findViewById(R.id.start_second);

        start_second.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });

        EventBus.getDefault().register(this);

    }


    @Subscribe(threadMode = ThreadMode.POSTING)
    public void showMessagePOSTINGEvent(MessageEvent messageEvent){
        show_message.setText("Message from SecondActivity" + "---" +messageEvent.getMessage());
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void showMessageMainEvent(MessageEvent messageEvent){
        show_message.setText("Message from SecondActivity" + "---" +messageEvent.getMessage());
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void showMessageBACKGROUNDEvent(MessageEvent messageEvent){
        show_message.setText("Message from SecondActivity" + "---" +messageEvent.getMessage());
    }

    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void showMessageASYNCEvent(MessageEvent messageEvent){
        show_message.setText("Message from SecondActivity" + "---" +messageEvent.getMessage());
    }


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

(2)Log如下:
D/MAIN: main
D/POSTING: main
D/ASYNC: pool-1-thread-1
D/BACKGROUND: pool-1-thread-2

從日志打印結果可以看出五辽,如果在UI線程中發(fā)布事件办斑,則線程模型為POSTING的事件處理函數也執(zhí)行在UI線程,與發(fā)布事件的線程一致。線程模型為ASYNC的事件處理函數執(zhí)行在名字叫做pool-1-thread-1的新的線程中乡翅。而MAIN的事件處理函數執(zhí)行在UI線程鳞疲,BACKGROUND的時間處理函數執(zhí)行在名字叫做pool-1-thread-2的新的線程中。

2.我們在子線程發(fā)送一條消息看看Log情況

button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                              Log.d("post", Thread.currentThread().getName());
                        EventBus.getDefault().post(new MessageEvent("NewMesage"));

                    }
                }).start();

            }

        });

Log如下:

D/post: Thread-153
D/BACKGROUND: Thread-153
D/POSTING: Thread-153
D/MAIN: main
D/ASYNC: pool-1-thread-1

從日志打印結果不難看出蠕蚜,如果在子線程中發(fā)布事件尚洽,則線程模型為POSTING的事件處理函數也執(zhí)行在子線程,與發(fā)布事件的線程一致靶累。BACKGROUND事件模型也與發(fā)布事件在同一線程執(zhí)行腺毫。ASYNC則在一個名叫pool-1-thread-1的新線程中執(zhí)行。MAIN還是在UI線程中執(zhí)行挣柬。

3.黏性事件##

黏性事件和我們的粘性廣播很類似潮酒,就是在發(fā)送事件之后再訂閱該事件也能收到該事件。

用法

(1)注冊粘性事件
EventBus.getDefault().register(MainActivity.this);
(2)處理粘性事件
@Subscribe(sticky = true)
public void XXX(MessageEvent messageEvent) {
    ......
}
(3)發(fā)送粘性事件
EventBus.getDefault().postSticky(new MessageEvent("message"));
(4)解除粘性事件
EventBus.getDefault().unregister(MainActivity.this);

示例:

屏幕快照 2017-09-16 15.48.51.png

當點擊Post Message按鈕發(fā)送粘性消息邪蛔,此時因為沒有注冊事件所以并沒有收到任何東西急黎,當點擊Regist EventBus按鈕進行注冊時就會收到之前發(fā)送的粘性消息,?并且此時我們每次點擊發(fā)送都會收到消息侧到,當我們點擊解除注冊Unregist EventBus按鈕的時候勃教,再次點擊Post Message也不會收到任何消息了。

代碼:

public class MainActivity extends AppCompatActivity {

    private Button post_btn, regist_btn, unregist_btn;
    private int index = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        post_btn = (Button) findViewById(R.id.post_message);
        regist_btn = (Button) findViewById(R.id.regist_seventbus);
        unregist_btn = (Button) findViewById(R.id.unregist_seventbus);

        post_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().postSticky(new MessageEvent("message" +
                        "---" +index++));
            }
        });

        regist_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().register(MainActivity.this);
            }
        });

        unregist_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                EventBus.getDefault().unregister(MainActivity.this);
            }
        });


    }


    @Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
    public void showMessagePOSTINGEvent(MessageEvent messageEvent){
        Log.d("POSTING",messageEvent.getMessage());
    }

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void showMessageMainEvent(MessageEvent messageEvent){
        Log.d("MAIN",messageEvent.getMessage());
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true)
    public void showMessageBACKGROUNDEvent(MessageEvent messageEvent){
        Log.d("BACKGROUND",messageEvent.getMessage());
    }

    @Subscribe(threadMode = ThreadMode.ASYNC, sticky = true)
    public void showMessageASYNCEvent(MessageEvent messageEvent){
        Log.d("ASYNC",messageEvent.getMessage());
    }
}

粘性事件就是這樣可以收到注冊之前發(fā)送的消息匠抗,但是它只能收到最新的一次消息故源,比如說在未注冊之前已經發(fā)送了多條黏性消息了,然后再注冊只能收到最近的一條消息戈咳。我們多次點擊發(fā)送消息之后點擊注冊來看一下Log心软。

D/MAIN: message---12
D/POSTING: message---12
D/BACKGROUND: message---12
D/ASYNC: message---12

可以看到我們只收到了最后一次點擊發(fā)送的消息。

尾語

學習到最后發(fā)現EventBus其實并不難著蛙,和我們之前用的廣播很類似,同樣需要注冊和解除注冊耳贬,處理消息的方法就類似于廣播接收者的onReceive()踏堡,同樣也可以選擇粘性性質。

參考資料

http://www.reibang.com/p/da9e193e8b03
http://blog.csdn.net/harvic880925/article/details/40660137

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末咒劲,一起剝皮案震驚了整個濱河市顷蟆,隨后出現的幾起案子,更是在濱河造成了極大的恐慌腐魂,老刑警劉巖帐偎,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異蛔屹,居然都是意外死亡削樊,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來漫贞,“玉大人甸箱,你說我怎么就攤上這事⊙钙辏” “怎么了芍殖?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長谴蔑。 經常有香客問我豌骏,道長,這世上最難降的妖魔是什么隐锭? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任肯适,我火速辦了婚禮,結果婚禮上成榜,老公的妹妹穿的比我還像新娘框舔。我一直安慰自己,他們只是感情好赎婚,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布刘绣。 她就那樣靜靜地躺著,像睡著了一般挣输。 火紅的嫁衣襯著肌膚如雪纬凤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天撩嚼,我揣著相機與錄音停士,去河邊找鬼。 笑死完丽,一個胖子當著我的面吹牛恋技,可吹牛的內容都是我干的。 我是一名探鬼主播逻族,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼蜻底,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了聘鳞?” 一聲冷哼從身側響起薄辅,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抠璃,沒想到半個月后站楚,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡搏嗡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年窿春,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡谁尸,死狀恐怖舅踪,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情良蛮,我是刑警寧澤抽碌,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站决瞳,受9級特大地震影響货徙,放射性物質發(fā)生泄漏。R本人自食惡果不足惜皮胡,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一痴颊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屡贺,春花似錦蠢棱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至量没,卻和暖如春玉转,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背殴蹄。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工究抓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人袭灯。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓刺下,卻偏偏與公主長得像,于是被迫代替她去往敵國和親妓蛮。 傳聞我的和親對象是個殘疾皇子怠李,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內容

  • 前言:EventBus出來已經有一段時間了,github上面也有很多開源項目中使用了EventBus蛤克。所以抽空學習...
    Kerry202閱讀 1,285評論 1 2
  • EventBus這個開源框架出來已經很久了,深的很多開發(fā)者青睞夷蚊,由greenrobot組織貢獻(該組織還貢獻了gr...
    Scus閱讀 2,235評論 0 0
  • 前言:EventBus出來已經有一段時間了构挤,github上面也有很多開源項目中使用了EventBus。所以抽空學習...
    Lauren_Liuling閱讀 48,459評論 23 155
  • 目錄 1.概述 2.實戰(zhàn) 1.基本框架搭建 2.新建一個類FirstEvent 3.在要接收消息的頁面注冊Even...
    慕涵盛華閱讀 10,502評論 2 16
  • 概述 EventBus是一個Android事件發(fā)布/訂閱框架惕鼓,通過解耦發(fā)布者和訂閱者簡化Android事件傳遞筋现,這...
    劉滌生閱讀 78,448評論 6 57