相關引用:
https://www.jianshu.com/p/a040955194fc
《Android進階之光》第七章
EventBus
出現的原因
EventBus是一款針對Android優化的事件釋出/訂閱架構,為了簡化并且高品質地在Activity、Fragment、Thread和Service之間通信,同時解決各元件之間高耦合的問題,同時仍能高效地通信。
傳統的事件傳遞方式包括:Handler、BroadcastReceiver、Interface回調,相比之下EventBus的優點是代碼簡潔,使用簡單,并将事件釋出和 訂閱充分解耦。
EventBus的組成部分
三要素
Event:事件。又叫消息,其實就是一個對象,可以是網絡請求傳回的字元串,也可以是某個開關狀态等等。事件類型EventType是指事件所屬的Class。
事件分為一般事件和Sticky事件,相對于一般事件,Sticky事件不同之處在于,當事件釋出後,再有訂閱者開始訂閱該類型事件,依然能收到該類型事件的最近一個Sticky事件。
Subscriber:事件訂閱者。在EventBus 3.0以後,事件處理的方法可以随便取名,但是需要添加一個注解@Subscribe,并且要指定線程模式(預設為POSTING)
Publisher:事件釋出者。可以在任意線程任意位置,通過post(MessageEvent)方法發送事件。可以自己執行個體化EventBus對象,但一般使用EventBus.getDefault()就可以。
EventBus是通過post函數傳進去的類的執行個體來确定調用哪個訂閱函數的,是哪個就調用哪個,如果有多個訂閱函數呢,那麼這些函數都會被調用!
四種ThreadMode
POSTING(預設):事件在哪個線程釋出,訂閱函數就會在哪個線程被調用,即釋出時間和接收事件在同一個線程。此時訂閱函數中盡量避免執行耗時操作,因為它會阻塞事件的傳遞,甚至有可能會引起ANR。
MAIN:訂閱函數在UI線程中執行。注意要避免ANR
BACKGROUND:表示如果事件在UI線程中釋出出來的,那麼訂閱函數onEvent就會在子線程中運作,如果事件本來就是在子線程中釋出出來的,那麼訂閱函數直接在該子線程中執行。
ASYNC:無論事件在哪個線程釋出,都會建立新的子線程來執行訂閱函數。
使用步驟
首先當然要在gradlew檔案添加EventBus的依賴啦:
implementation 'org.greenrobot:eventbus:3.1.1'
- 定義一個事件:
public static class MessageEvent { /* Additional fields if needed */ }
- 在事件訂閱者類上:注冊和登出您的訂閱者。例如,在Android上,Activity和Fragment通常應根據其生命周期進行注冊:
聲明并且注解你的訂閱函數,注解中可選擇指定的ThreadMode:@Override public void onStart(){ super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop(){ super.onStop(); // 不再使用時,請登出 EventBus.getDefault().unregister(this); }
@Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event){ /* Do something */ };
- 發送事件:
EventBus.getDefault().post(new MessageEvent());
最後ProGuard混淆:
-keepattributes *Annotation*
-keepclassmembers class * {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}
Demo
建立事件MessageEvent類:
package com.example.wudongjiang.eventbusdemo;
public class MessageEvent {
private String msg;
public MessageEvent(String msg){
this.msg = msg;
}
public String getMsg(){
return this.msg;
}
public void setMsg(String msg){
this.msg = msg;
}
}
MainActivity:
package com.example.wudongjiang.eventbusdemo;
import android.content.Intent;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
public class MainActivity extends AppCompatActivity {
private TextView mTv_show_text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTv_show_text = findViewById(R.id.tv_show_text);
findViewById(R.id.btn_register).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().register(MainActivity.this);
}
});
findViewById(R.id.btn_go_to_second_activity).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this,SecondActivity.class));
}
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event){
boolean isMainThread = (Looper.myLooper() == getMainLooper());
Toast.makeText(this,"是否運作在UI線程?"+isMainThread,Toast.LENGTH_SHORT).show();
mTv_show_text.setText(event.getMsg());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(MainActivity.this);
}
}
SecondActivity:
package com.example.wudongjiang.eventbusdemo;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import org.greenrobot.eventbus.EventBus;
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.btn_post_event).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().post(new MessageEvent("發送事件"));
}
});
}
}
運作結果:
EventBus的黏性事件
所謂黏性事件,就是在發送事件之後,再訂閱該事件,也能收到,跟黏性廣播類似。可修改上述代碼驗證。
MainActivity:
package com.example.wudongjiang.eventbusdemo;
import android.content.Intent;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
public class MainActivity extends AppCompatActivity {
private TextView mTv_show_text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTv_show_text = findViewById(R.id.tv_show_text);
findViewById(R.id.btn_register).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().register(MainActivity.this);
}
});
findViewById(R.id.btn_go_to_second_activity).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, SecondActivity.class));
}
});
}
/**
* 普通事件
*
* @param event
*/
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
boolean isMainThread = (Looper.myLooper() == getMainLooper());
Toast.makeText(this, "是否運作在UI線程?" + isMainThread, Toast.LENGTH_SHORT).show();
mTv_show_text.setText(event.getMsg());
}
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true)
public void onMessageStickyEvent(MessageEvent event) {
boolean isMainThread = (Looper.myLooper() == getMainLooper());
Toast.makeText(this, "是否運作在UI線程?" + isMainThread, Toast.LENGTH_SHORT).show();
mTv_show_text.setText(event.getMsg());
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(MainActivity.this);
}
}
SecondActivity:
package com.example.wudongjiang.eventbusdemo;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import org.greenrobot.eventbus.EventBus;
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.btn_post_event).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().post(new MessageEvent("發送事件"));
}
});
findViewById(R.id.btn_post_sticky_event).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().postSticky(new MessageEvent("發送黏性事件"));
}
});
}
}
運作結果:
首先不再MainActivity點選注冊事件,就直接跳轉到SecondActivity,點選發送黏性事件。此時傳回到MainActivity,是沒有msg顯示的,因為我們還沒有點選訂閱,然後點選MainActivity的注冊事件,就有相應的Text顯示了,說明接收成功:
源碼分析
EventBus 3.0 源碼分析