相关引用:
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通常应根据其生命周期进行注册:
@Override public void onStart(){ super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop(){ super.onStop(); // 不再使用时,请注销 EventBus.getDefault().unregister(this); }
声明并且注解你的订阅函数,注解中可选择指定的ThreadMode:
@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显示了,说明接收成功: