Android開源專案EventBus3.0的使用
前言:
EventBus,是一個針對Android優化的事件訂閱/發表開源專案,可以替代Intent,,BroadCast在Fragment,Activity,Service,執行緒之間傳遞訊息.優點是開銷小,程式碼更優雅,以及將傳送者和接收者解耦。
EventBus3.0下載:EventBus3.0,將下載的jar包引入專案中就可以使用了。
正確的使用步驟:
- 註冊事件訂閱者(”登入”)
- 傳送方傳送訊息(傳遞資料)
- 接收方處理訊息(處理資料)
- 解除註冊(”登出”)
1. 註冊事件訂閱者(”登入”)
// 1.註冊事件訂閱者("登入")
EventBus.getDefault().register(this );
這裡將當前的這個物件註冊到EventBus事件匯流排中,在android中通常是在Application、Activity、Service、Fragment的onCreate方法中進行。
如:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1.註冊事件訂閱者("登入")
EventBus.getDefault().register(this );
}
2. 傳送方傳送訊息(傳遞資料)
// 2.傳送方傳送訊息 -- 傳送MainMessage這個自己定義的物件,可以豐富這個物件,用來傳遞訊息(資料)
EventBus.getDefault().post(new MainMessage("Hello EventBus"));
// 2.傳送方傳送訊息 -- 傳送BackgroundMessage這個自己定義的物件,可以豐富這個物件,用來傳遞訊息(資料)
EventBus.getDefault().post(new BackgroundMessage("Hello EventBus"));
// 2.傳送方傳送訊息 -- 傳送AsyncMessage這個自己定義的物件,可以豐富這個物件,用來傳遞訊息(資料)
EventBus.getDefault().post(new AsyncMessage("Hello EventBus"));
// 2.傳送方傳送訊息 -- 傳送PostMessage這個自己定義的物件,可以豐富這個物件,用來傳遞訊息(資料)
EventBus.getDefault().post(new PostMessage("Hello EventBus"));
注:這三段程式碼都屬於第二步,只不過傳送的訊息物件型別(類)不同,這裡的訊息物件MainMessage,BackgroundMessage,AsyncMessage和PostMessage是我們自己定義的用來傳遞訊息(資料)的物件,可以自行豐富(這些訊息物件之間沒有繼承關係,是不同型別的物件)。
而這些物件的原始碼(這裡都類似,自行豐富):
package com.example.eventbus;
public class MainMessage {
private String msg;
public MainMessage(String msg){
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
3. 接收方處理訊息(處理資料)
// 3.接收方處理訊息(處理資料)-- 主執行緒中執行
@Subscribe(threadMode = ThreadMode.MainThread)
public void onMainEventBus(MainMessage msg) {
Log.d(TAG, "onEventBus() handling message: " + Thread.currentThread().getName());
}
// 3.接收方處理訊息(處理資料)-- 後臺執行緒或子執行緒中執行
@Subscribe(threadMode = ThreadMode.BackgroundThread)
public void onBackgroundEventBus(BackgroundMessage msg) {
Log.d(TAG, "onEventBusBackground() handling message: " + Thread.currentThread().getName());
}
// 3.接收方處理訊息(處理資料)-- 後臺執行緒中執行
@Subscribe(threadMode = ThreadMode.Async)
public void onAsyncEventBus(AsyncMessage msg) {
Log.d(TAG, "onEventBusAsync() handling message: " + Thread.currentThread().getName());
}
// 3.接收方處理訊息(處理資料)-- 和傳送方在同一個執行緒
@Subscribe(threadMode = ThreadMode.PostThread)
public void onPostEventBus(PostMessage msg) {
Log.d(TAG, "onEventBusPost() handling message: " + Thread.currentThread().getName());
}
注:
- 這三段程式碼都屬於第三步,分別對應第二步中傳送的不同訊息物件型別;
- 方法引數的物件型別很重要,EventBus會根據這裡的引數物件型別判斷應該呼叫哪個回撥方法(可能是多個),也就是說上面的第二步中傳送的4種不同型別的物件會分別回撥對應引數型別的那個事件處理方法。這裡判斷對應引數型別是根據傳送的物件訊息型別是否是方法引數物件的型別或者子類(這也就是為什麼在第二步中說明那4個訊息物件是不同型別,沒有繼承關係),如果傳送的物件訊息型別是方法引數物件的型別或者子類,那麼就會回撥這個方法(順序是先本類再父類);
- 事件處理方法上面的註解
@Subscribe(threadMode = ThreadMode.*)
必不可少,是為了指定當前處理方法的執行緒模型,即:
- @Subscribe(threadMode = ThreadMode.MainThread):不管傳送方在那個執行緒傳送的訊息,接收方(處理方)都在主執行緒中處理訊息(資料),注意主執行緒不要被阻塞;
- @Subscribe(threadMode = ThreadMode.BackgroundThread):如果傳送方在主執行緒中傳送訊息,那麼接收方(處理方)就會在後臺執行緒中處理訊息,否則在和傳送方相同的那個子執行緒中處理訊息(資料);
- @Subscribe(threadMode = ThreadMode.Async):強制接收方(處理方)在後臺執行緒中處理訊息(資料);
- @Subscribe(threadMode = ThreadMode.PostThread):和傳送方在相同的執行緒中處理訊息(資料)。
- 方法名可以任意,只要符合命名規則就行;
- 注意,後臺執行緒可以有多個,即如果一個後臺執行緒被阻塞後新的訊息到達後會在一個新的後臺執行緒處理訊息。
4. 解除註冊(”登出”)
// 4.解除註冊("登出")
EventBus.getDefault().unregister(this);
這裡將當前的這個物件從EventBus事件匯流排中解除註冊,在android中通常是在Activity、Service和Fragment的onDestroy方法中進行。
如:
@Override
protected void onDestroy() {
super.onDestroy();
// 4.解除註冊("登出")
EventBus.getDefault().unregister(this);
}
完成這四步後,接下來就看看專案的完整程式碼:
MainActivity.java
package com.example.eventbus;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import de.greenrobot.event.EventBus;
import de.greenrobot.event.Subscribe;
import de.greenrobot.event.ThreadMode;
public class MainActivity extends Activity {
private final static String TAG = "EventBusTest";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1.註冊事件訂閱者("登入")
EventBus.getDefault().register(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 4.解除註冊("登出")
EventBus.getDefault().unregister(this);
}
public void testActivity(View view){
Intent intent = new Intent(this,TestActivity.class);
startActivity(intent);
}
// 3.接收方處理訊息(處理資料)-- 主執行緒中執行
@Subscribe(threadMode = ThreadMode.MainThread)
public void onMainEventBus(MainMessage msg) {
Log.d(TAG, "onEventBus() handling message: " + Thread.currentThread().getName());
}
// 3.接收方處理訊息(處理資料)-- 後臺執行緒或子執行緒中執行
@Subscribe(threadMode = ThreadMode.BackgroundThread)
public void onBackgroundEventBus(BackgroundMessage msg) {
Log.d(TAG, "onEventBusBackground() handling message: " + Thread.currentThread().getName());
}
// 3.接收方處理訊息(處理資料)-- 後臺執行緒中執行
@Subscribe(threadMode = ThreadMode.Async)
public void onAsyncEventBus(AsyncMessage msg) {
Log.d(TAG, "onEventBusAsync() handling message: " + Thread.currentThread().getName());
}
// 3.接收方處理訊息(處理資料)-- 和傳送方在同一個執行緒
@Subscribe(threadMode = ThreadMode.PostThread)
public void onPostEventBus(PostMessage msg) {
Log.d(TAG, "onEventBusPost() handling message: " + Thread.currentThread().getName());
}
}
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:gravity="center"
android:orientation="vertical">
<Button
android:onClick="testActivity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="testActivity"
/>
</LinearLayout>
OtherActivity.java(注意在清單檔案裡註冊哦)
package com.example.eventbus;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import de.greenrobot.event.EventBus;
public class OtherActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.other_activity);
}
public void btnClick(View view) {
switch (view.getId()) {
case R.id.btn1:
// 2.傳送方傳送訊息 -- 傳送MainMessage這個自己定義的物件,可以豐富這個物件,用來傳遞訊息(資料)
EventBus.getDefault().post(new MainMessage("Hello EventBus"));
break;
case R.id.btn2:
// 2.傳送方傳送訊息 -- 傳送BackgroundMessage這個自己定義的物件,可以豐富這個物件,用來傳遞訊息(資料)
// 注意,這裡是在主執行緒中傳送訊息
EventBus.getDefault().post(new BackgroundMessage("Hello EventBus"));
break;
case R.id.btn3:
new Thread(){
public void run() {
// 2.傳送方傳送訊息 -- 傳送AsyncMessage這個自己定義的物件,可以豐富這個物件,用來傳遞訊息(資料)
EventBus.getDefault().post(new AsyncMessage("Hello EventBus"));
};
}.start();
break;
case R.id.btn4:
new Thread(){
public void run() {
// 2.傳送方傳送訊息 -- 傳送PostMessage這個自己定義的物件,可以豐富這個物件,用來傳遞訊息(資料)
EventBus.getDefault().post(new PostMessage("Hello EventBus"));
};
}.start();
break;
}
}
}
other_activity.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/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="btnClick"
android:text="傳送訊息強制接收方在主執行緒處理訊息"/>
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="btnClick"
android:text="傳送訊息讓接收方在後臺執行緒或子執行緒處理訊息"/>
<Button
android:id="@+id/btn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="btnClick"
android:text="傳送訊息強制接收方在後臺執行緒中處理訊息"/>
<Button
android:id="@+id/btn4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="btnClick"
android:text="傳送訊息讓接收方在傳送方所在的執行緒處理訊息"/>
</LinearLayout>
這裡可能會問,為什麼不在一個activity中進行傳送訊息和處理訊息呢?其實,這裡我這樣做是為了說明,EventBus起的作用和Broadcast作用一樣,可以使得不同的Activity進行通訊,對比使用上也可以發現同樣需要註冊和取消註冊,關於裡面的原理,可能是通過觀察者模式來實現的吧。
接下來,我們就只需要觀察測試結果了:
執行起這個程式,在OtherActivity中分別點選四個按鈕,然後觀察日誌列印:
到這裡,EventBus的基本使用已經說完了,如果文章中有什麼不理解或是遇到什麼困惑的話不妨自己動手實驗一下,畢竟實驗是檢驗真理的唯一標準!這裡是本文演示的專案下載地址,方便下載測試: