01 前言
當(dāng)我們進(jìn)行項(xiàng)目開(kāi)發(fā)的時(shí)候,往往是需要應(yīng)用程序的各組件、組件與后臺(tái)線程間進(jìn)行通信,比如在子線程中進(jìn)行請(qǐng)求數(shù)據(jù),當(dāng)數(shù)據(jù)請(qǐng)求完畢后通過(guò)Handler或者是廣播通知UI,而兩個(gè)Fragment之家可以通過(guò)Listener進(jìn)行通信等等。當(dāng)我們的項(xiàng)目越來(lái)越復(fù)雜,使用Intent、Handler、Broadcast進(jìn)行模塊間通信、模塊與后臺(tái)線程進(jìn)行通信時(shí),代碼量大,而且高度耦合?,F(xiàn)在就讓我們來(lái)學(xué)習(xí)一下EventBus 3.0吧。
02 什么是EventBus
EventBus Github地址
進(jìn)入官網(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能夠簡(jiǎn)化各組件間的通信,讓我們的代碼書(shū)寫(xiě)變得簡(jiǎn)單,能有效的分離事件發(fā)送方和接收方(也就是解耦的意思),能避免復(fù)雜和容易出錯(cuò)的依賴性和生命周期問(wèn)題。
03 關(guān)于EventBus的概述
三要素
- Event 事件。它可以是任意類(lèi)型。
- Subscriber 事件訂閱者。在EventBus3.0之前我們必須定義以onEvent開(kāi)頭的那幾個(gè)方法,分別是onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,而在3.0之后事件處理的方法名可以隨意取,不過(guò)需要加上注解@subscribe(),并且指定線程模型,默認(rèn)是POSTING。
- Publisher 事件的發(fā)布者。我們可以在任意線程里發(fā)布事件,一般情況下,使用EventBus.getDefault()就可以得到一個(gè)EventBus對(duì)象,然后再調(diào)用post(Object)方法即可。
四種線程模型
EventBus3.0有四種線程模型,分別是:
- POSTING (默認(rèn)) 表示事件處理函數(shù)的線程跟發(fā)布事件的線程在同一個(gè)線程。
- MAIN 表示事件處理函數(shù)的線程在主線程(UI)線程,因此在這里不能進(jìn)行耗時(shí)操作。
- BACKGROUND 表示事件處理函數(shù)的線程在后臺(tái)線程,因此不能進(jìn)行UI操作。如果發(fā)布事件的線程是主線程(UI線程),那么事件處理函數(shù)將會(huì)開(kāi)啟一個(gè)后臺(tái)線程,如果果發(fā)布事件的線程是在后臺(tái)線程,那么事件處理函數(shù)就使用該線程。
- ASYNC 表示無(wú)論事件發(fā)布的線程是哪一個(gè),事件處理函數(shù)始終會(huì)新建一個(gè)子線程運(yùn)行,同樣不能進(jìn)行UI操作。
04 EventBus的基本用法
舉個(gè)例子,我需要在一個(gè)Activity里注冊(cè)EventBus事件,然后定義接收方法,這跟Android里的廣播機(jī)制很像,你需要首先注冊(cè)廣播,然后需要編寫(xiě)內(nèi)部類(lèi),實(shí)現(xiàn)接收廣播,然后操作UI。所以,在EventBus中,你同樣得這么做。
自定義一個(gè)事件類(lèi)
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;
}
}
這里有些同學(xué),會(huì)有一些疑問(wèn),為什么要建立這樣一個(gè)類(lèi),有什么用途。其實(shí)這個(gè)類(lèi)就是一個(gè)Bean類(lèi),里面定義用來(lái)傳輸?shù)臄?shù)據(jù)的類(lèi)型。
注冊(cè)事件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
}
當(dāng)我們需要在Activity或者Fragment里訂閱事件時(shí),我們需要注冊(cè)EventBus。我們一般選擇在Activity的onCreate()方法里去注冊(cè)EventBus,在onDestory()方法里,去解除注冊(cè)。
解除注冊(cè)
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
發(fā)送事件
EventBus.getDefault().post(messageEvent);
處理事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void XXX(MessageEvent messageEvent) {
...
}
前面我們說(shuō)過(guò),處理消息的方法名字可以隨便取。但是需要加一個(gè)注解@Subscribe,并且要指定線程模型。
4.1 EventBus用法之:粘性事件
所謂粘性事件,就是在發(fā)送事件之后再訂閱該事件也能收到該事件。請(qǐng)注意這里與普通事件的區(qū)別,普通事件是先注冊(cè)在綁定。
比如在項(xiàng)目中有這樣的需求,在FirstActivity發(fā)送事件,到SecondActivity中做事件的處理。如果是使通過(guò)EventBus.getDefault.post(xx)發(fā)出的,在SecondActivity是接收不到消息的。 主要原因是SecondActivit用于接收消息的EventBus還未完成注冊(cè),也就是發(fā)布者發(fā)了消息,但訂閱者還未產(chǎn)生。
發(fā)送粘性事件
EventBus.getDefault().postSticky(messageEvent);
以Sticky的形式發(fā)送的事件,在注冊(cè)對(duì)象也要通過(guò)Sticky的形式進(jìn)行處理事件
處理粘性事件
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void XXX(MessageEvent messageEvent) {
...
}
剩下的注冊(cè)操作和解綁操作和發(fā)送普通事件是一樣的
05 EventBus使用實(shí)戰(zhàn)
以上我們講了EventBus的基本用法,沒(méi)有用過(guò)的同學(xué)也不要擔(dān)心不會(huì)用,小編在這里舉個(gè)小栗子。
第一步:添加依賴
compile 'org.greenrobot:eventbus:3.0.0'
第二步:定義消息事件類(lèi)
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;
}
}
第三步:注冊(cè)和解除注冊(cè)
分別在FirstActivity的onCreate()方法和onDestory()方法里,進(jìn)行注冊(cè)EventBus和解除注冊(cè)。
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);
}
}
}
事件處理
在這里,事件的處理線程在主線程,是因?yàn)?,我要讓TextView去顯示值。
在 SecondActivity里去進(jìn)行事件的發(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("歡迎大家瀏覽我寫(xiě)的博客"));
finish();
}
});
}
}
很簡(jiǎn)單,當(dāng)點(diǎn)擊按鈕的時(shí)候,發(fā)送了一個(gè)事件。
運(yùn)行程序。
這是SecondActivity,在頁(yè)面的左上角,是一個(gè)按鈕,當(dāng)點(diǎn)擊按鈕,就會(huì)發(fā)送了一個(gè)事件,最后這個(gè)Activity就會(huì)銷(xiāo)毀掉。
此時(shí)我們可以看到,F(xiàn)irstActivity里的文字已經(jīng)變成了,我們?cè)赟econdActivity里設(shè)置的文字。
總結(jié)
經(jīng)過(guò)這個(gè)簡(jiǎn)單的例子,我們發(fā)現(xiàn)EventBus使用起來(lái)是如此的方便,當(dāng)我們的代碼量變得很多的時(shí)候,使用EventBus后你的邏輯非常的清晰,并且代碼之間高度解耦,在進(jìn)行組件、頁(yè)面間通信的時(shí)候,EventBus是一個(gè)不錯(cuò)的選擇。