EventBus事件總線分發庫
本文圍繞如下六個部分展開:
1、事件總線管理
2、EventBus
3、EventBus與BroadcastReceiver的區別
案例一
案例二:一處點擊發送數據,另外一處或多處註冊點能夠及時獲取更新傳輸過來的數據
案例三:Activity和Service之間互相發佈與接收事件
1、事件總線管理
將事件放入隊列裏,用於管理和分發。
(1)保證應用的各個部分之間高效的通訊及數據、事件分發。
(2)模塊間解耦:經過事件的分發,可讓各個模塊間關聯程序變小。
當在開發一些龐大的的項目時,模塊比較多,這個時候爲了不耦合度和保證 APP 的效率,會用到 EventBus 等相似的事件總線處理模型。這樣能夠簡化一些數據傳輸操做,保證APP的簡潔,作到高內聚、低耦合。
2、EventBus
1. 概念
EventBus是一個發佈/訂閱的事件總線。它可讓兩個組件相互通訊,可是它們之間並不相互知曉。
EventBus模式,也被稱爲 Message Bus模式,或者 發佈者/訂閱者(publisher/subscriber)模式。
事件響應有更多的線程選擇,EventBus 能夠向不一樣的線程中發佈事件。
EventBus 支持 Sticky Event。
2. 有3個主要的元素:
(1)Event:事件。
Event能夠是任意類型的對象。
(2)Subscriber:事件訂閱者,接收特定的事件。
在EventBus中,使用約定來指定事件訂閱者以簡化使用。即,全部事件訂閱都是以onEvent開頭的函數。具體來講,函數的名字是onEventMainThread,onEventPostThread,onEventBackgroundThread,onEventAsync這四個,onEvent是默認的接收數據處理的方法。這四個事件訂閱函數,每一個都與一個「ThreadMode」相關聯,ThreadMode指定了會調用的函數。有如下4個ThreadMode:
1)PostThread:事件的處理和事件的發送在相同的進程。
事件處理時間不該太長,否則影響事件的發送線程,而這個線程多是UI線程。對應的函數名是onEvent。
2)MainThread:事件的處理會在UI線程中執行。
事件處理時間不該太長,長了會ANR的。對應的函數名是onEventMainThread。
3)BackgroundThread:事件的處理會在一個後臺線程中執行。
雖然事件處理是在後臺線程,但事件處理時間仍是不該該太長,由於若是發送事件的線程是後臺線程,會直接執行事件。若是當前線程是UI線程,事件會被加到一個隊列中,由一個線程依次處理這些事件,若是某個事件處理時間太長,會阻塞後面的事件的派發或處理。對應的函數名是onEventBackgroundThread。
4)AsyncThread:事件處理會在單獨的線程中執行。
主要用於在後臺線程中執行耗時操做,每一個事件會開啓一個線程(有線程池),但最好限制線程的數目。
根據事件訂閱的函數名稱的不一樣,會使用不一樣的ThreadMode。好比在後臺線程加載了數據想在UI線程顯示,訂閱者只需把函數命名爲onEventMainThread。
3. 基本用法
分 註冊、訂閱、發佈、取消註冊 等步驟。使用時需先註冊、訂閱,而後向訂閱者發佈消息數據便可。
(1)註冊(3個構造方法):
EventBus.getDefault().register(this);
EventBus.getDefault().register(new MyClass());
// 註冊三個參數分別是:消息訂閱者(接收者),接收方法名,事件類。
EventBus.getDefault().register(this,"setTextA",SetTextAEvent.class);
(2)註銷註冊:
EventBus.getDefault().unregister(this);
EventBus.getDefault().unregister(new MyClass());
(3)定義事件類型:
public class MyEvent {}
(4)訂閱處理數據:
public void onEvent(AnyEventType event){}:默認的接收數據處理的方法
public void onEventMainThread{}
onEventPostThread
onEventBackgroundThread
onEventAsync
(5)發佈:
EventBus.getDefault().postSticky(new SecondActivityEvent("Message from SecondActivity"));
EventBus.getDefault().post(new ChangeImgEvent(1));
3、EventBus與BroadcastReceiver的區別
1. 兩者相似。
在Android中廣播分爲兩個方面:廣播發送者和廣播接收者,一般狀況下,BroadcastReceiver指的就是廣播接收者(廣播接收器)。
廣播:在一個地方註冊廣播,在另外一個地方針對action發送廣播、傳遞數據,對應註冊的地方就能夠收到廣播。
EventBus:基於訂閱/發佈的模式。在須要接收數據的地方,進行註冊與訂閱,在須要發佈數據的地方發佈,則在註冊的地方就能夠收到了。
簡單點說,就是兩人約定好怎麼通訊,一人發佈消息,另一個約定好的人立馬接收到你發的消息。EventBus就能夠幫助減小作不少事,無論你在任何地方任何位置發佈一個事件,接收者都能立馬接收到你的消息,不用你考慮android子線程操做UI線程的問題。
2. 兩者區別。
(1)EventBus 有三個主要的元素:事件、訂閱和發佈。廣播兩個元素:訂閱和發佈,可是廣播是針對整個App而言的。
(2)BroadcastReceiver是組件,須要在功能清單中註冊。而EventBus 不須要註冊。
(3)BroadcastReceiver只能作一件事情,而EventBus多事件處理比較好。
(4)在不一樣場景中的適用性:
1)同一App內部的同一組件內的消息通訊(單個或多個線程之間),實際應用中確定是不會用到廣播機制的(雖然能夠用),不管是使用擴展變量做用域、基於接口的回調仍是Handler-post/Handler-Message等方式,均可以直接處理此類問題,若使用廣播機制,顯然有些「殺雞牛刀」的感受。
2)同一app內部的不一樣組件之間的消息通訊(單個進程),對於此類需求,在有些教複雜的狀況下單純的依靠基於接口的回調等方式很差處理,此時能夠直接使用EventBus等,相對而言,EventBus因爲是針對同一進程,用於處理此類需求很是適合,且輕鬆。
3)其餘情形,因爲涉及不一樣進程間的消息通訊,此時根據實際業務使用廣播機制會顯得很是適宜。
案例一
MainActivity
Java代碼
- public class MainActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- // 1. 註冊
- EventBus.getDefault().register(this);
- }
-
- /**
- * 3. 發送數據消息事件
- */
- private void postData() {
- String string = "我是消息";
- EventBus.getDefault().post(string);
- }
-
- /**
- * 2. 接收數據消息事件
- */
- public void onEvent(String string) {
-
- }
-
- public void onEventMainThread(String string) {
-
- }
-
- public void onEventPostThread(String string) {
-
- }
-
- public void onEventBackgroundThread(String string) {
-
- }
-
- public void onEventAsync(String string) {
-
- }
-
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- // 4. 取消註冊
- EventBus.getDefault().unregister(this);
- }
-
- }
案例二:一處點擊發送數據,另外一處或多處註冊點能夠及時獲取更新傳輸過來的數據
1. activity_main.xml。寫一個按鈕和一個文本框。
Xml代碼
- <RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context=".MainActivity">
-
- <Button
- android:id="@+id/btnSend"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="發送事件"/>
-
- <TextView
- android:id="@+id/tvContent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/btnSend"
- android:gravity="center"
- android:textSize="20sp"/>
-
- </RelativeLayout>
2. MainActivity。聲明和初始化兩個控件。
Java代碼
- private TextView tvContent;
- private Button btnSend;
Java代碼
- tvContent = (TextView) findViewById(R.id.tvContent);
- btnSend = (Button) findViewById(R.id.btnSend);
3. MainActivity。onCreate()方法中註冊。
Java代碼
- EventBus.getDefault().register(this);
4. MainActivity。onDestroy()方法中取消註冊。
Java代碼
- @Override
- protected void onDestroy() {
- super.onDestroy();
- EventBus.getDefault().unregister(this);
- }
5. MainActivity。經過事件監聽器設置按鈕的點擊事件。
Java代碼
- btnSend.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
-
- }
- });
6. 建立自定義的事件類:MyEvent。
Java代碼
- package com.android.eventbustwo;
-
- /**
- * 自定義的事件類
- */
- public class MyEvent {
- private String type;
- private String content;
-
- public String getType() {
- return type;
- }
-
- public void setType(String type) {
- this.type = type;
- }
-
- public String getContent() {
- return content;
- }
-
- public void setContent(String content) {
- this.content = content;
- }
- }
7. MainActivity。在按鈕點擊事件中,建立自定義事件類MyEvent的實例事件,並當點擊按鈕的時候,發送事件。
Java代碼
- btnSend.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- MyEvent event = new MyEvent();
- event.setType("0");
- event.setContent("0內容");
- // 發送數據事件
- EventBus.getDefault().post(event);
- }
- });
8. MainActivity。經過onEvent()訂閱(接收)事件。
Java代碼
- public void onEvent(MyEvent event){
- if(event.getType().equals("0")){
- tvContent.setText(event.getContent());
- }
- }
運行效果以下:
9. MainActivity。在按鈕點擊事件中,將事件類型和內容改變,並當點擊按鈕的時候,發送事件。
Java代碼
- btnSend.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- MyEvent event = new MyEvent();
- event.setType("1");
- event.setContent("1內容");
- // 發送數據事件
- EventBus.getDefault().post(event);
- }
- });
10. MainActivity。經過onEventMainThread()一樣能夠訂閱(接收)事件。
Java代碼
- public void onEventMainThread(MyEvent event){
- if(event.getType().equals("1")){
- tvContent.setText(event.getContent());
- }
- }
運行效果以下:
代碼補充:
1. activity_main.xml
2. MainActivity
Java代碼
- package com.android.eventbustwo;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
-
- import de.greenrobot.event.EventBus;
-
- public class MainActivity extends Activity {
- // 2.
- private TextView tvContent;
- private Button btnSend;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- // 3.
- tvContent = (TextView) findViewById(R.id.tvContent);
- btnSend = (Button) findViewById(R.id.btnSend);
- // 6.
- btnSend.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // 8.
- MyEvent event = new MyEvent();
- event.setType("0");
- event.setContent("0內容");
- // 發送數據事件
- EventBus.getDefault().post(event);
- }
- });
- // 4.
- EventBus.getDefault().register(this);
- }
-
- /**
- * 9.
- * @param event
- */
- public void onEvent(MyEvent event){
- if(event.getType().equals("0")){
- tvContent.setText(event.getContent());
- }
- }
-
- /**
- * 10.
- * @param event
- */
- public void onEventMainThread(MyEvent event){
- if(event.getType().equals("1")){
- tvContent.setText(event.getContent());
- }
- }
-
- /**
- * 5.
- */
- @Override
- protected void onDestroy() {
- super.onDestroy();
- EventBus.getDefault().unregister(this);
- }
-
- // -----------------------------------------------------------
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.menu_main, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
-
- //noinspection SimplifiableIfStatement
- if (id == R.id.action_settings) {
- return true;
- }
-
- return super.onOptionsItemSelected(item);
- }
- }
3. MyEvent
Java代碼
- package com.android.eventbustwo;
-
- /**
- * 7. 自定義的事件類
- */
- public class MyEvent {
- private String type;
- private String content;
-
- public String getType() {
- return type;
- }
-
- public void setType(String type) {
- this.type = type;
- }
-
- public String getContent() {
- return content;
- }
-
- public void setContent(String content) {
- this.content = content;
- }
- }
案例三:Activity和Service之間互相發佈與接收事件
主活動有4家公司名顯示,當在文本框中輸入「Amazon」,點擊按鈕後,將新的公司名顯示在主活動界面上。
1. 建立一個Service: EventService。
2. EventService。將onBind中的異常去掉,改成 返回null。
Java代碼
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
3. activity_main.xml。一個顯示的文本框,用於顯示Service發佈的事件;一個可編輯文本框,用於輸入字符串,併發布事件到Service;一個按鈕,經過點擊按鈕,發佈事件,而後Service進行訂閱。
Xml代碼
- <RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- tools:context=".MainActivity">
-
- <TextView
- android:id="@+id/tvCompany"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/hello_world" />
-
- <EditText
- android:id="@+id/txtCompany"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/tvCompany"
- android:hint="@string/txt_company" />
-
- <Button
- android:id="@+id/btnCompany"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtCompany"
- android:text="@string/btn_send_company" />
-
- </RelativeLayout>
4. EventService。重寫onCreate()、onStartCommand()、onDestroy()方法。
5. EventService。聲明一個 List 集合,用於放公司名的集合,並在onCreate()方法中建立實例(ArrayList類型)。
Java代碼
- private List<String> list;
Java代碼
- list = new ArrayList<>();
6. EventService。在onStartCommand()方法中,往List集合中添加元素(公司名)。銷燬(onDestroy())的時候,集合設爲null。
Java代碼
- list.add("Google");
- list.add("Facebook");
- list.add("Twitter");
- list.add("Apple");
Java代碼
- list = null;
8. EventService。onCreate()中註冊EventBus,onDestroy()銷燬時註銷註冊。
Java代碼
- EventBus.getDefault().register(this);
Java代碼
- EventBus.getDefault().unregister(this);
9. MainActivity。onCreate()中一樣註冊EventBus,onDestroy()銷燬時一樣註銷註冊。
10. 新建一個目錄:event,用來放事件類。
11. 在event目錄下,新建一個用於從 Service 發佈集合數據(公司名的集合)集合事件類:ListEvent。
Java代碼
- public class ListEvent {
- // 集合
- private List<String> list;
-
- // 含參構造方法
- public ListEvent(List<String> list) {
- this.list = list;
- }
-
- // getter方法(只需getter方法)
- public List<String> getList() {
- return list;
- }
- }
12. 在event目錄下,新建一個用於從 Activity 發佈字符串(公司名)的集合事件類:CompanyEvent。
Java代碼
- public class CompanyEvent {
- // 字符串 company
- private String company;
-
- // 含參構造方法
- public CompanyEvent(String company) {
- this.company = company;
- }
-
- // getter方法(只需getter方法)
- public String getCompany() {
- return company;
- }
- }
13. MainActivity。在按鈕點擊事件中,發佈事件。
Java代碼
- @OnClick(R.id.btnCompany)
- public void btnCompanyClick() {
- // 得到 在 txtCompany 文本框中輸入的 company 字符串 的值
- String company = txtCompany.getText().toString();
- // Activity 發佈事件 --- 將 在 txtCompany 文本框中輸入的 company 字符串,
- // 使用 CompanyEvent 發佈過去
- EventBus.getDefault().post(new CompanyEvent(company));
- // 發佈以後,將 文本框內容清空
- txtCompany.setText("");
- }
14. EventService。Service訂閱事件,將Activity發佈的公司名加入List集合中。而後,再將最新的公司名List集合發佈出去。
Java代碼
- /**
- * Service 訂閱事件
- * @param event
- */
- public void onEvent(CompanyEvent event){
- // 將 事件中傳過來的、在 txtCompany 文本框中輸入的 company 字符串,放入 list集合中
- list.add(event.getCompany());
- // 再將 list集合,發佈給 Activity,
- // 這樣,Activity訂閱後,就能夠在 控制檯和界面上 顯示最新的 list集合的值
- EventBus.getDefault().postSticky(new ListEvent(list));
- }
15. MainActivity。Activity 訂閱了ListEvent事件,因此接收到了Service發佈的公司名List集合的值,而後將其顯示在控制檯和界面的文本上。
Java代碼
- /**
- * Activity 訂閱事件
- *
- * @param event
- */
- public void onEvent(ListEvent event) {
- // 從Service發佈的事件中得到 參數值(list集合)
- List<String> list = event.getList();
- // 日誌輸出 list集合的值 (控制檯顯示 list集合的值)
- Log.v(TAG, list.toString());
- // 將 list集合的值 顯示在 tvCompany 文本中。(界面的文本上 顯示 list集合的值)
- tvCompany.setText(list.toString());
- }
代碼目錄結構:
補充代碼:
(1)EventService。
Java代碼
- package com.android.eventbusservice;
-
- import android.app.Service;
- import android.content.Intent;
- import android.os.IBinder;
- import android.util.Log;
-
- import com.android.eventbusservice.event.CompanyEvent;
- import com.android.eventbusservice.event.ListEvent;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import de.greenrobot.event.EventBus;
-
- public class EventService extends Service {
- private static final String TAG = "MainActivity";
- // 聲明一個 List 集合 -- 用於放公司名的集合
- private List<String> list;
-
- public EventService() {
- }
-
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.v(TAG,"Service.onCreate");
- // 當前組件註冊事件
- // (註冊事件後,必定要有 onEvent() 方法,不然報錯)
- EventBus.getDefault().register(this);
- // 建立實例 - ArrayList類型
- list = new ArrayList<>();
- }
-
- /**
- * 此方法系統自動調用,不寫也可。可把裏面的代碼寫入 onCreate()裏面。
- */
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- Log.v(TAG,"Service.onStartCommand");
- // 往集合中添加元素
- list.add("Google");
- list.add("Facebook");
- list.add("Twitter");
- list.add("Apple");
-
- // Service 發佈事件 -- 將 list 集合,使用 ListEvent 發送過去
- // (ListEvent:用於從 Service 傳事件到 Activity)
- EventBus.getDefault().postSticky(new ListEvent(list));
- // 改成:返回 START_STICKY
- return START_STICKY;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.v(TAG, "Service.onDestroy");
- // 銷燬的時候,取消事件
- EventBus.getDefault().unregister(this);
- // 銷燬的時候,集合設爲空
- list = null;
- }
-
- /**
- * Service 訂閱事件
- * @param event
- */
- public void onEvent(CompanyEvent event){
- // 將 事件中傳過來的、在 txtCompany 文本框中輸入的 company 字符串,放入 list集合中
- list.add(event.getCompany());
- // 再將 list集合,發佈給 Activity,
- // 這樣,Activity訂閱後,就能夠在 控制檯和界面上 顯示最新的 list集合的值
- EventBus.getDefault().postSticky(new ListEvent(list));
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- }
(2)MainActivity。
Java代碼
- package com.android.eventbusservice;
-
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.widget.EditText;
- import android.widget.TextView;
-
- import com.android.eventbusservice.event.CompanyEvent;
- import com.android.eventbusservice.event.ListEvent;
-
- import java.util.List;
-
- import butterknife.ButterKnife;
- import butterknife.InjectView;
- import butterknife.OnClick;
- import de.greenrobot.event.EventBus;
-
- public class MainActivity extends Activity {
- private static final String TAG = "MainActivity";
-
- @InjectView(R.id.tvCompany)
- TextView tvCompany;
- @InjectView(R.id.txtCompany)
- EditText txtCompany;
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- ButterKnife.inject(this);
-
- // 在 Activity 中一樣註冊事件
- EventBus.getDefault().register(this);
-
- // 啓動服務 -- 使用 startService 方式啓動
- // 啓動服務後,activity與service脫鉤了。
- // 可是能夠經過黃油刀進行聯繫。
- startService(new Intent(this, EventService.class));
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- // 在 Activity 中一樣註銷事件
- EventBus.getDefault().unregister(this);
- }
-
- @OnClick(R.id.btnCompany)
- public void btnCompanyClick() {
- // 得到 在 txtCompany 文本框中輸入的 company 字符串 的值
- String company = txtCompany.getText().toString();
- // Activity 發佈事件 --- 將 在 txtCompany 文本框中輸入的 company 字符串,
- // 使用 CompanyEvent 發佈過去
- EventBus.getDefault().post(new CompanyEvent(company));
- // 發佈以後,將 文本框內容清空
- txtCompany.setText("");
- }
-
- /**
- * Activity 訂閱事件
- *
- * @param event
- */
- public void onEvent(ListEvent event) {
- // 從Service發佈的事件中得到 參數值(list集合)
- List<String> list = event.getList();
- // 日誌輸出 list集合的值 (控制檯顯示 list集合的值)
- Log.v(TAG, list.toString());
- // 將 list集合的值 顯示在 tvCompany 文本中。(界面的文本上 顯示 list集合的值)
- tvCompany.setText(list.toString());
- }
-
- // ---------------------------------------------------------
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.menu_main, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
-
- //noinspection SimplifiableIfStatement
- if (id == R.id.action_settings) {
- return true;
- }
-
- return super.onOptionsItemSelected(item);
- }
- }
整理時重點參考:http://www.jikexueyuan.com/course/933.html
歡迎關注本站公眾號,獲取更多信息