EventBus使用詳解

目錄

1.概述
2.實戰(zhàn)
  • 1.基本框架搭建
  • 2.新建一個類FirstEvent
  • 3.在要接收消息的頁面注冊EventBus
  • 4.發(fā)送消息
  • 5.接收消息
3.線程模型

EventBus使用詳解(一)——EventBus核心內容

一.概述

當一個Android應用功能越來越多的時候,保證應用的各個部分之間高效的通信將變得越來越困難。所以為了解決這個問題,EventBus應運而生!
EventBus是一款針對Android優(yōu)化的發(fā)布/訂閱事件總線。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息.優(yōu)點是開銷小,代碼更優(yōu)雅,它簡化了組件之間的通信,使我們的應用程序更加簡單、通信更加快捷。我們來看EventBus的消息傳遞圖:

EventBus的消息傳遞圖
EventBus事件主線由四大部分組成:

<b>Publisher發(fā)布者</b>:用于分發(fā)我們的Event事件,在EventBus中通過post方法進行分發(fā)傳送。

<b>Subscriber訂閱者:</b>用于接受我們的事件,我們在訂閱事件中處理我們接收的數(shù)據(jù)。

<b>Event事件:</b>任何一個對象都可以作為事件,比如任何字符串,事件是發(fā)布者和訂閱者之間的通信載體。

<b>EventBus:</b>類似于中轉站,將我們的事件進行對應的分發(fā)處理。

舉個通俗點的例子,EventBus消息機制就是我們生活中的寄快遞,你去快遞站點寄快遞,你就是事件發(fā)送者,你的包裹就是事件,快遞站點就是EventBus,接收快遞的人就是事件訂閱者??爝f公司經過裝車分類最后把你的快遞寄到收件人手里,就類似EventBus最后將事件成功傳達。

1、下載EventBus的類庫

源碼:https://github.com/greenrobot/EventBus.git

2、基本使用

(1)首先需要定義一個消息類,該類可以不繼承任何基類也不需要實現(xiàn)任何接口

public class MessageEvent {
 ......
 }

(2)在需要訂閱事件的地方注冊事件

EventBus.getDefault().register(this);

(3)產生事件,即發(fā)送消息

EventBus.getDefault().post(messageEvent);

(4)處理消息

在3.0之前,EventBus還沒有使用注解方式。消息處理的方法也只能限定于onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,分別代表四種線程模型。而在3.0之后,消息處理的方法可以隨便取名,但是需要添加一個注解@Subscribe,并且要指定線程模型(默認為POSTING),四種線程模型,下面會講到。

注意,事件處理函數(shù)的訪問權限必須為public,否則會報異常。

@Subscribe(threadMode = ThreadMode.POSTING)
public void XXX(MessageEvent messageEvent){
    ... 
}

(5)取消消息訂閱

  EventBus.getDefault().unregister(this);

二.實戰(zhàn)

先給大家看個例子:

當擊btn_try按鈕的時候,跳到第二個Activity,當點擊第二個activity上面的First Event按鈕的時候向第一個Activity發(fā)送消息,當?shù)谝粋€Activity收到消息后,一方面將消息Toast顯示,一方面放入textView中顯示。

Demo.gif
1、基本框架搭建

想必大家從一個Activity跳轉到第二個Activity的程序應該都會寫,這里先稍稍把兩個Activity跳轉的代碼建起來。后面再添加EventBus相關的代碼。

MainActivity布局(activity_main.xml)

<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">  

  <Button   
    android:id="@+id/btn_try"  
    android:layout_width="match_parent"  
    android:layout_height="wrap_content"  
    android:text="btn_bty"/>

  <TextView   
    android:id="@+id/tv"  
    android:layout_width="wrap_content"  
    android:layout_height="match_parent"/>  
</LinearLayout>  

新建一個Activity,SecondActivity布局(activity_second.xml)

<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.harvic.try_eventbus_1.SecondActivity" >  

  <Button   
    android:id="@+id/btn_first_event"  
    android:layout_width="match_parent"  
    android:layout_height="wrap_content"  
    android:text="First Event"/>  
</LinearLayout>  

MainActivity.java (點擊btn跳轉到第二個Activity)

public class MainActivity extends Activity {  
Button btn;  

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

    btn = (Button) findViewById(R.id.btn_try);  

    btn.setOnClickListener(new View.OnClickListener() {  

    @Override  
    public void onClick(View v) {  
        // TODO Auto-generated method stub  
        Intent intent = new Intent(getApplicationContext(),  
        SecondActivity.class);  
        startActivity(intent);  
    }  
    });  
}  
}  

到這,基本框架就搭完了,下面開始按步驟使用EventBus了。

2、新建一個消息事件類MessageEvent
public class MessageEvent {

private String message;

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

public String getMessage() {
    return message;
}
}  

這個類很簡單,構造時傳進去一個字符串,然后可以通過getMessage()獲取出來。

3、在要接收消息的頁面注冊EventBus:

在上面的GIF圖片的演示中,大家也可以看到,我們是要在MainActivity中接收發(fā)過來的消息的,所以我們在MainActivity中注冊消息。

通過我們會在OnCreate()函數(shù)中注冊EventBus,在OnDestroy()函數(shù)中反注冊。所以整體的注冊與反注冊的代碼如下:

public class MainActivity extends Activity {  

Button btn;  
TextView tv;  

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

    btn = (Button) findViewById(R.id.btn_try);  
    tv = (TextView)findViewById(R.id.tv);  

    btn.setOnClickListener(new View.OnClickListener() {  

    @Override  
    public void onClick(View v) {  
        // TODO Auto-generated method stub  
        Intent intent = new Intent(getApplicationContext(),  
        SecondActivity.class);  
        startActivity(intent);  
        }  
        });  
    }  
@Override  
protected void onDestroy(){  
    super.onDestroy();  
    EventBus.getDefault().unregister(this);//反注冊EventBus  
}  
}  
4、發(fā)送消息

發(fā)送消息是使用EventBus中的Post方法來實現(xiàn)發(fā)送的,發(fā)送過去的是我們新建的類的實例!

EventBus.getDefault().post(new MessageEvent("Btn clicked"));  

完整的SecondActivity.java的代碼如下:

package com.example.tryeventbus_simple;  

import com.harvic.other.FirstEvent;  
import de.greenrobot.event.EventBus;  
import android.app.Activity;  
import android.os.Bundle;  
import android.view.View;  
import android.widget.Button;  

public class SecondActivity extends Activity {  
private Button btn_FirstEvent;  

@Override  
protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
    setContentView(R.layout.activity_second);  
    btn_FirstEvent = (Button) findViewById(R.id.btn_first_event);  

    btn_FirstEvent.setOnClickListener(new View.OnClickListener() {  

    @Override  
    public void onClick(View v) {  
    // TODO Auto-generated method stub  
    EventBus.getDefault().post(  
    new FirstEvent("FirstEvent btn clicked"));  
    }  
    });  
}  
}  
5、接收消息

接收消息時,我們使用EventBus中最常用的ThreadMode.MAIN線程模式來接收消息,具體為什么用這個,我們下篇再講,這里先給大家一個初步認識,要先能把EventBus用起來先。 在MainActivity中聲明一個公共的加注釋的方法,參數(shù)就是我們自己定義的類:

在收到Event實例后,我們將其中攜帶的消息取出,一方面Toast出去,一方面?zhèn)鞯絋extView中;

@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(MessageEvent event) {  
  String msg = "onEventMainThread收到了消息:" + event.getMessage();  
  Log.d("EventBus", msg);  
  tv.setText(msg);  
  Toast.makeText(this, msg, Toast.LENGTH_LONG).show();  
}  

完整的MainActiviy代碼如下:

public class MainActivity extends AppCompatActivity {

Button mBtn;
TextView mTv;

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

    EventBus.getDefault().register(this);//注冊EventBus

    mBtn = (Button) findViewById(R.id.main_btn);
    mTv = (TextView) findViewById(R.id.main_tv);

    mBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent();
            intent.setClass(getApplicationContext(),SecondActivity.class);
            startActivity(intent);
        }
    });
}

@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(MessageEvent event) {
    String msg = "onEventMainThread收到了消息:" + event.getMessage();
    Log.d("EventBus", msg);
    mTv.setText(msg);
    Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}

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

EventBus使用詳解(二)——EventBus拓展內容

線程模型

在EventBus的事件處理函數(shù)中需要指定線程模型,即指定事件處理函數(shù)運行所在的想線程。在上面我們已經接觸到了EventBus的四種線程模型。那他們有什么區(qū)別呢? 在EventBus中的觀察者通常有四種線程模型,分別是PostThread(默認)、MainThread、BackgroundThread與Async。

<b>POSTING:</b>如果使用事件處理函數(shù)指定了線程模型為PostThread,那么該事件在哪個線程發(fā)布出來的,事件處理函數(shù)就會在這個線程中運行,也就是說發(fā)布事件和接收事件在同一個線程。在線程模型為PostThread的事件處理函數(shù)中盡量避免執(zhí)行耗時操作,因為它會阻塞事件的傳遞,甚至有可能會引起ANR。
<b>MAIN:</b>如果使用事件處理函數(shù)指定了線程模型為MainThread,那么不論事件是在哪個線程中發(fā)布出來的,該事件處理函數(shù)都會在UI線程中執(zhí)行。該方法可以用來更新UI,但是不能處理耗時操作。
<b>BACKGROUND:</b>如果使用事件處理函數(shù)指定了線程模型為BackgroundThread,那么如果事件是在UI線程中發(fā)布出來的,那么該事件處理函數(shù)就會在新的線程中運行,如果事件本來就是子線程中發(fā)布出來的,那么該事件處理函數(shù)直接在發(fā)布事件的線程中執(zhí)行。在此事件處理函數(shù)中禁止進行UI更新操作。
<b>ASYNC:</b>如果使用事件處理函數(shù)指定了線程模型為Async,那么無論事件在哪個線程發(fā)布,該事件處理函數(shù)都會在新建的子線程中執(zhí)行。同樣,此事件處理函數(shù)中禁止進行UI更新操作。
為了驗證以上四個方法,我寫了個小例子。

@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessageEventPostThread(MessageEvent messageEvent) {
    Log.e("POSTING", Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEventMainThread(MessageEvent messageEvent) {
    Log.e("MAIN", Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessageEventBackgroundThread(MessageEvent messageEvent) {
    Log.e("BACKGROUND", Thread.currentThread().getName());
}

@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessageEventAsync(MessageEvent messageEvent) {
    Log.e("ASYNC", Thread.currentThread().getName());
}

分別使用上面四個方法訂閱同一事件,打印他們運行所在的線程。首先我們在UI線程中發(fā)布一條MessageEvent的消息,看下日志打印結果是什么。

findViewById(R.id.send).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.e("POSTING", Thread.currentThread().getName());
        EventBus.getDefault().post(new MessageEvent(“test”));
    }
});

打印結果如下:

04-13 08:18:31.361 6627-6627/com.example.administrator.explain_eventbus E/POSTING: main
04-31 08:18:31.361 6627-6687/com.example.administrator.explain_eventbus E/ASYNC: pool-1-thread-1
04-13 08:18:31.365 6627-6627/com.example.administrator.explain_eventbus E/MAIN: main
04-13 08:18:31.365 6627-6627/com.example.administrator.explain_eventbus E/POSTING: main
04-13 08:18:31.365 6627-6688/com.example.administrator.explain_eventbus E/BACKGROUND: pool-1-thread-2

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

我們再看看在子線程中發(fā)布一條MessageEvent的消息時,會有什么樣的結果。

findViewById(R.id.send).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.e("POSTING", Thread.currentThread().getName());
                EventBus.getDefault().post(new MessageEvent(“test”));
            }
        }).start();
    }
});

打印結果如下:

04-13 08:27:24.705 12468-14509/com.example.administrator.explain_eventbus E/POSTING: Thread-120
04-13 08:27:24.705 12468-14447/com.example.administrator.explain_eventbus E/ASYNC: pool-1-thread-1
04-13 08:27:24.709 12468-14509/com.example.administrator.explain_eventbus E/BACKGROUND: Thread-120
04-13 08:27:24.709 12468-14509/com.example.administrator.explain_eventbus E/POSTING: Thread-120
04-13 08:27:24.721 12468-12468/com.example.administrator.explain_eventbus E/MAIN: main

從日志打印結果可以看出,如果在子線程中發(fā)布事件,則線程模型為POSTING的事件處理函數(shù)也執(zhí)行在子線程,與發(fā)布事件的線程一致(都是Thread-120)。BACKGROUND事件模型也與發(fā)布事件在同一線程執(zhí)行。ASYNC則在一個名叫pool-1-thread-1的新線程中執(zhí)行。MAIN還是在UI線程中執(zhí)行。

上面一個例子充分驗證了指定不同線程模型的事件處理方法執(zhí)行所在的線程。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容