01 前言
當我們進行項目開發(fā)的時候,往往是需要應用程序的各組件、組件與后臺線程間進行通信,比如在子線程中進行請求數(shù)據(jù),當數(shù)據(jù)請求完畢后通過Handler或者是廣播通知UI,而兩個Fragment之家可以通過Listener進行通信等等。當我們的項目越來越復雜,使用Intent、Handler、Broadcast進行模塊間通信、模塊與后臺線程進行通信時,代碼量大,而且高度耦合?,F(xiàn)在就讓我們來學習一下EventBus 3.0吧。
02 什么是EventBus
EventBus Github地址
進入官網(wǎng),看看人家是怎么解釋的:
- simplifies the communication between components
decouples event senders and receivers
performs well with Activities, Fragments, and background threads
avoids complex and error-prone dependencies and life cycle issues- makes your code simpler
- is fast
- is tiny (~50k jar)
- is proven in practice by apps with 100,000,000+ installs
- has advanced features like delivery threads, subscriber priorities, etc.
大概的意思就是:EventBus能夠簡化各組件間的通信,讓我們的代碼書寫變得簡單,能有效的分離事件發(fā)送方和接收方(也就是解耦的意思),能避免復雜和容易出錯的依賴性和生命周期問題。
03 關于EventBus的概述
三要素
- Event 事件。它可以是任意類型。
- Subscriber 事件訂閱者。在EventBus3.0之前我們必須定義以onEvent開頭的那幾個方法,分別是onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,而在3.0之后事件處理的方法名可以隨意取,不過需要加上注解@subscribe(),并且指定線程模型,默認是POSTING。
- Publisher 事件的發(fā)布者。我們可以在任意線程里發(fā)布事件,一般情況下,使用EventBus.getDefault()就可以得到一個EventBus對象,然后再調用post(Object)方法即可。
四種線程模型
EventBus3.0有四種線程模型,分別是:
- POSTING (默認) 表示事件處理函數(shù)的線程跟發(fā)布事件的線程在同一個線程。
- MAIN 表示事件處理函數(shù)的線程在主線程(UI)線程,因此在這里不能進行耗時操作。
- BACKGROUND 表示事件處理函數(shù)的線程在后臺線程,因此不能進行UI操作。如果發(fā)布事件的線程是主線程(UI線程),那么事件處理函數(shù)將會開啟一個后臺線程,如果果發(fā)布事件的線程是在后臺線程,那么事件處理函數(shù)就使用該線程。
- ASYNC 表示無論事件發(fā)布的線程是哪一個,事件處理函數(shù)始終會新建一個子線程運行,同樣不能進行UI操作。
04 EventBus的基本用法
舉個例子,我需要在一個Activity里注冊EventBus事件,然后定義接收方法,這跟Android里的廣播機制很像,你需要首先注冊廣播,然后需要編寫內部類,實現(xiàn)接收廣播,然后操作UI。所以,在EventBus中,你同樣得這么做。
自定義一個事件類
public class MessageEvent{
private String message;
public MessageEvent(String message){
this.message=message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
這里有些同學,會有一些疑問,為什么要建立這樣一個類,有什么用途。其實這個類就是一個Bean類,里面定義用來傳輸?shù)臄?shù)據(jù)的類型。
注冊事件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
}
當我們需要在Activity或者Fragment里訂閱事件時,我們需要注冊EventBus。我們一般選擇在Activity的onCreate()方法里去注冊EventBus,在onDestory()方法里,去解除注冊。
解除注冊
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
發(fā)送事件
EventBus.getDefault().post(messageEvent);
處理事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void XXX(MessageEvent messageEvent) {
...
}
前面我們說過,處理消息的方法名字可以隨便取。但是需要加一個注解@Subscribe,并且要指定線程模型。
4.1 EventBus用法之:粘性事件
所謂粘性事件,就是在發(fā)送事件之后再訂閱該事件也能收到該事件。請注意這里與普通事件的區(qū)別,普通事件是先注冊在綁定。
比如在項目中有這樣的需求,在FirstActivity發(fā)送事件,到SecondActivity中做事件的處理。如果是使通過EventBus.getDefault.post(xx)發(fā)出的,在SecondActivity是接收不到消息的。 主要原因是SecondActivit用于接收消息的EventBus還未完成注冊,也就是發(fā)布者發(fā)了消息,但訂閱者還未產生。
發(fā)送粘性事件
EventBus.getDefault().postSticky(messageEvent);
以Sticky的形式發(fā)送的事件,在注冊對象也要通過Sticky的形式進行處理事件
處理粘性事件
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void XXX(MessageEvent messageEvent) {
...
}
剩下的注冊操作和解綁操作和發(fā)送普通事件是一樣的
05 EventBus使用實戰(zhàn)
以上我們講了EventBus的基本用法,沒有用過的同學也不要擔心不會用,小編在這里舉個小栗子。
第一步:添加依賴
compile 'org.greenrobot:eventbus:3.0.0'
第二步:定義消息事件類
public class MessageEvent{
private String message;
public MessageEvent(String message){
this.message=message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
第三步:注冊和解除注冊
分別在FirstActivity的onCreate()方法和onDestory()方法里,進行注冊EventBus和解除注冊。
package com.example.lenovo.testapp.ui;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.example.lenovo.testapp.R;
import com.example.lenovo.testapp.event.MessageEvent;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
/**
* Created by ZZG on 2018/1/10.
*/
public class FirstActivity extends AppCompatActivity {
private Button mButton;
private TextView mText;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_activity);
mButton = (Button) findViewById(R.id.btn1);
mText = (TextView) findViewById(R.id.tv1);
mText.setText("今天是星期三");
EventBus.getDefault().register(this);
jumpActivity();
}
private void jumpActivity() {
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
}
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void Event(MessageEvent messageEvent) {
mText.setText(messageEvent.getMessage());
}
@Override
protected void onDestroy() {
super.onDestroy();
if(EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
}
}
事件處理
在這里,事件的處理線程在主線程,是因為,我要讓TextView去顯示值。
在 SecondActivity里去進行事件的發(fā)送。
package com.example.lenovo.tezs;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import org.greenrobot.eventbus.EventBus;
/**
* Created by ZZG on 2018/1/10.
*/
public class SecondActivity extends AppCompatActivity {
private Button mButton2;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity);
mButton2=(Button) findViewById(R.id.btn2);
jumpActivity();
}
private void jumpActivity() {
mButton2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().post(new MessageEvent("歡迎大家瀏覽我寫的博客"));
finish();
}
});
}
}
很簡單,當點擊按鈕的時候,發(fā)送了一個事件。
運行程序。
這是SecondActivity,在頁面的左上角,是一個按鈕,當點擊按鈕,就會發(fā)送了一個事件,最后這個Activity就會銷毀掉。
此時我們可以看到,F(xiàn)irstActivity里的文字已經(jīng)變成了,我們在SecondActivity里設置的文字。
總結
經(jīng)過這個簡單的例子,我們發(fā)現(xiàn)EventBus使用起來是如此的方便,當我們的代碼量變得很多的時候,使用EventBus后你的邏輯非常的清晰,并且代碼之間高度解耦,在進行組件、頁面間通信的時候,EventBus是一個不錯的選擇。