EventBus事件總線

什么是EventBus:
EventBus是android下的高效的發(fā)布/訂閱總線機制,它的作用是可以代替?zhèn)鹘y(tǒng)的Intent,Handler,Broadcast,或者接口函數在Fragment,Activity,Service,線程之間傳遞數據,執(zhí)行方法,它用來傳遞數據特別方便,并且代碼簡潔,實現了代碼之間的解耦.是一種發(fā)布訂閱者模式,或者稱為觀察者設計模式
來一張EventBus的github上的框架原理流程圖

圖片1.png

怎么使用EventBus:
1.引入EventBus,這里有兩種方法,一種是下載EventBus庫源碼地址:https://github.com/greenrobot/EventBus, 庫地址:https://github.com/greenrobot/EventBus/releases, ,將EventBus的jar文件放入libs中,第二中方法是直接在build.gradle中添加依賴, compile 'org.greenrobot:eventbus:3.0.0',

2.定義事件,前面已經說了,EventBus是事件發(fā)布總線,用來傳遞消息的,那么我們需要定義要傳遞的消息.定義一個類,繼承默認的Object即可,用來區(qū)分事件和傳遞數據,

3.添加訂閱者,一個類用成為訂閱者類,就必須注冊, EventBus.getDefault().register(this);通過注冊成為訂閱者之后,框架會通過反射機制獲取所有的方法和參數.
那么訂閱者是怎么接收發(fā)布者發(fā)布的事件的,這里就要講一下不同版本的EventBus的訂閱者接收事件的方法不一樣了,EventBus2.4的時候訂閱者所在的類可以定義以下一個或多個方法用以接收事件:

    public void onEvent(MsgEvent1 msg)// 與發(fā)布者在同一個線程
    public void onEventMainThread(MsgEvent1 msg)// 執(zhí)行在主線程。
    public void onEventBackgroundThread(MsgEvent1 msg)// 執(zhí)行在子線程古劲,如果發(fā)布者是子線程則直接執(zhí)行该默,如果發(fā)布者不是子線程把鉴,則創(chuàng)建一個再執(zhí)行
    public void onEventAsync(MsgEvent1 msg)// 執(zhí)行在在一個新的子線程

而在EventBus3.0之后就取消了約定好的方法定義,并提供了注解的方式進行監(jiān)聽.

     @Subscribe(threadMode = ThreadMode.MAIN)
     public void getEventBus(MyEvent event){
     }

threadMode就是舊版本接收信息運行的方法。

4.發(fā)布者發(fā)布事件,所有類都可以成為發(fā)布者,訂閱者也可以作為發(fā)布者給自己發(fā)布消息, EventBus.getDefault().post(new MsgEvent1("主線程發(fā)的消息1"));一旦執(zhí)行了此方法, 所有訂閱者都會執(zhí)行第二步定義的方法阵具。

5.取消訂閱,一般訂閱者銷毀的時候在銷毀的生命周期方法中可以取消訂閱,不再接收消息, EventBus.getDefault().unregister(this)
需要注意的是發(fā)布者可以發(fā)布任何事件, 訂閱者接受消息時,只要定義的是第二步四個方法任意一個定铜,并且參數和發(fā)布者發(fā)布的一致阳液,即可被執(zhí)行。發(fā)布者也可以通過第二步接收消息揣炕,訂閱者也可以作為發(fā)布者發(fā)消息給自己趁舀。

下面通過一個Demo更好的認識EventBus:

引入EventBus,這里我用的是gradle的方式:

  compile 'org.greenrobot:eventbus:3.0.0'

主界面:

   /**因為主界面中要實現左邊一個fragment,右邊一個fragment,所以繼承FragmentActivity*/
public class MainActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.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:divider="?android:attr/dividerHorizontal"
          android:orientation="horizontal"
          android:showDividers="middle"
          android:baselineAligned="false"
          tools:context=".MainActivity" >

<fragment
    android:id="@+id/left_fragment"
    android:name="com.xinguangnet.eventdemo.LeftFragment"
    android:layout_width="0dip"
    android:layout_height="match_parent"
    android:layout_weight="1" />

<fragment
    android:id="@+id/right_fragment"
    android:name="com.xinguangnet.eventdemo.RightFragment"
    android:layout_width="0dip"
    android:layout_height="match_parent"
    android:layout_weight="3" />

</LinearLayout>

定義事件:

public class MsgEvent1 {
private String msg;

public MsgEvent1(String msg) {
    super();
    this.msg = msg;
}
public String getMsg() {
    return msg;
}
}

右邊的fragment,作為接收者:
創(chuàng)建的時候注冊,銷毀的時候取消注冊:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//界面創(chuàng)建時就訂閱事件接收消息
EventBus.getDefault().register(this);
}

@Override
public void onDestroy() {
super.onDestroy();
//界面銷毀時取消訂閱
EventBus.getDefault().unregister(this);
}

接收事件的方法:

/**
 * 與發(fā)布者在同一個線程
 * @param msg 事件1
 */
@Subscribe
public void onEvent(MsgEvent1 msg){
String content = msg.getMsg()
        + "\n ThreadName: " + Thread.currentThread().getName()
        + "\n ThreadId: " + Thread.currentThread().getId();
System.out.println("onEvent(MsgEvent1 msg)收到" + content);
}

/**
 * 執(zhí)行在主線程。
 * 非常實用祝沸,可以在這里將子線程加載到的數據直接設置到界面中矮烹。
 * @param msg 事件1
 */
@Subscribe
public void onEventMainThread(MsgEvent1 msg){
    String content = msg.getMsg()
            + "\n ThreadName: " + Thread.currentThread().getName()
              + "\n ThreadId: " + Thread.currentThread().getId();
    System.out.println("onEventMainThread(MsgEvent1 msg)收到" + content);
    tv.setText(content);
}

/**
 * 執(zhí)行在子線程越庇,如果發(fā)布者是子線程則直接執(zhí)行,如果發(fā)布者不是子線程奉狈,則創(chuàng)建一個再執(zhí)行
 * 此處可能會有線程阻塞問題卤唉。
 * @param msg 事件1
 */
@Subscribe
public void onEventBackgroundThread(MsgEvent1 msg){
    String content = msg.getMsg()
            + "\n ThreadName: " + Thread.currentThread().getName()
            + "\n ThreadId: " + Thread.currentThread().getId();
    System.out.println("onEventBackgroundThread(MsgEvent1 msg)收到" + content);
}

/**
 * 執(zhí)行在在一個新的子線程
 * 適用于多個線程任務處理, 內部有線程池管理仁期。
 * @param msg 事件1
 */
@Subscribe
public void onEventAsync(MsgEvent1 msg){
    String content = msg.getMsg()
            + "\n ThreadName: " + Thread.currentThread().getName()
            + "\n ThreadId: " + Thread.currentThread().getId();
    System.out.println("onEventAsync(MsgEvent1 msg)收到" + content);
}

/**
 * 與發(fā)布者在同一個線程
 * @param msg 事件2
 */
@Subscribe
public void onEvent(MsgEvent2 msg){
    String content = msg.getMsg()
        + "\n ThreadName: " + Thread.currentThread().getName()
        + "\n ThreadId: " + Thread.currentThread().getId();
System.out.println("onEvent(MsgEvent2 msg)收到" + content);
tv.setText(content);
}

左邊的fragment用來發(fā)布消息:

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
String[] strs = new String[]{"主線程消息1", "子線程消息1", "主線程消息2"};
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, strs));
}

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
switch (position) {
    case 0:
        // 主線程
        System.out.println(
                "----------------------主線程發(fā)的消息1"
                        + " threadName: " + Thread.currentThread().getName()
                        + " threadId: " + Thread.currentThread().getId());
        EventBus.getDefault().post(new MsgEvent1("主線程發(fā)的消息1"));
        break;
    case 1:
        // 子線程
        new Thread() {
            public void run() {
                System.out.println(
                        "----------------------子線程發(fā)的消息1"
                                + " threadName: " + Thread.currentThread().getName()
                                + " threadId: " + Thread.currentThread().getId());
                EventBus.getDefault().post(new MsgEvent1("子線程發(fā)的消息1"));
            }

            ;
        }.start();

        break;
    case 2:
        // 主線程
        System.out.println(
                "----------------------主線程發(fā)的消息2"
                        + " threadName: " + Thread.currentThread().getName()
                        + " threadId: " + Thread.currentThread().getId());
        EventBus.getDefault().post(new MsgEvent2("主線程發(fā)的消息2"));
        break;
}
}

這個Demo寫完之后運行起來有一個出現了bug,我開始百思不得其解,后來反復看了錯誤日志,終于知道了原因

Paste_Image.png

我引入的EventBus3.0但是一開始在訂閱者的接收方法里面沒有加注解,所以報了以上的錯誤

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末桑驱,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子跛蛋,更是在濱河造成了極大的恐慌熬的,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赊级,死亡現場離奇詭異押框,居然都是意外死亡,警方通過查閱死者的電腦和手機理逊,發(fā)現死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門橡伞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晋被,你說我怎么就攤上這事兑徘。” “怎么了羡洛?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵挂脑,是天一觀的道長。 經常有香客問我欲侮,道長崭闲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任锈麸,我火速辦了婚禮镀脂,結果婚禮上,老公的妹妹穿的比我還像新娘忘伞。我一直安慰自己薄翅,他們只是感情好,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布氓奈。 她就那樣靜靜地躺著翘魄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舀奶。 梳的紋絲不亂的頭發(fā)上暑竟,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天,我揣著相機與錄音,去河邊找鬼但荤。 笑死罗岖,一個胖子當著我的面吹牛,可吹牛的內容都是我干的腹躁。 我是一名探鬼主播桑包,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼纺非!你這毒婦竟也來了哑了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤烧颖,失蹤者是張志新(化名)和其女友劉穎弱左,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體炕淮,經...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡黄橘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年绍昂,在試婚紗的時候發(fā)現自己被綠了蛉腌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溶锭。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡优妙,死狀恐怖乘综,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情套硼,我是刑警寧澤卡辰,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站邪意,受9級特大地震影響九妈,放射性物質發(fā)生泄漏。R本人自食惡果不足惜雾鬼,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一萌朱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧策菜,春花似錦晶疼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蠢莺,卻和暖如春寒匙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背躏将。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工锄弱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留考蕾,地道東北人。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓会宪,卻偏偏與公主長得像辕翰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子狈谊,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內容

  • EventBus EventBus 是一個 Android 事件發(fā)布/訂閱框架喜命,通過解耦發(fā)布者和訂閱者簡化 And...
    凱玲之戀閱讀 1,837評論 0 1
  • 今天突然得知有事件總線這個東西,正好又在等后臺調接口河劝,就去網上搜羅一個這方面的學習資料學習一下壁榕,然后我就震...
    緣狄閱讀 850評論 1 7
  • EventBus 是一個Android端優(yōu)化的 publish/subscribe 消息總線,簡化了應用程序各個組...
    王世軍Steven閱讀 1,855評論 4 21
  • 項目到了一定階段會出現一種甜蜜的負擔:業(yè)務的不斷發(fā)展與人員的流動性越來越大,代碼維護與測試回歸流程越來越繁瑣赎瞎。這個...
    fdacc6a1e764閱讀 3,186評論 0 6
  • 今天晨讀資料分享的書籍是——《美在舉手投足間》牌里,對于三個分享內容,我概括為——行為务甥、對己牡辽、待人。 花的美麗在于綻放...
    5070黑土閱讀 317評論 10 4