eventBus使用和及源码初步梳理
一、eventbus简介
EventBus是一种用于Android的事件发布-订阅总线,由GreenRobot开发。它简化了应用程序内各个组件、线程之间进行通信的复杂度,尤其是碎片之间进行通信的问题,可以避免由于使用广播通信而带来的诸多不便。
1.1 三个重要角色
Event:事件对象,它可以是任意类型,EventBus会根据事件类型进行全局的通知。
Subscriber:事件订阅者,在EventBus 3.0之前我们必须定义以onEvent开头的那几个方法,分别是onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,而在3.0之后事件处理的方法名可以随意取,不过需要加上注解@subscribe,并且指定线程模型,默认是POSTING。
Publisher:事件的发布者,可以在任意线程里发布事件。一般情况下,使用EventBus.getDefault()就可以得到一个EventBus对象,然后再调用post(Object)方法即可。
1.2 四种线程模型
EventBus3.0有四种线程模型,分别是:
POSTING:默认,表示事件处理函数的线程跟发布事件的线程在同一个线程。
MAIN:表示事件处理函数的线程在主线程(UI)线程,因此在这里不能进行耗时操作。
BACKGROUND:表示事件处理函数的线程在后台线程,因此不能进行UI操作。
ASYNC:表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个子线程运行,同样不能进行UI操作。
二、EventBus 使用
2.1 先要引入如下依赖:
implementation 'org.greenrobot:eventbus:3.1.1'
2.2 定义注册事件类型
public class MessageWrap {
public final String message;
public static MessageWrap getInstance(String message) {
return new MessageWrap(message);
}
private MessageWrap(String message) {
this.message = message;
}
}
2.3 注册事件监听
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
Button btn;
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = findViewById(R.id.btnRegister);
tv = findViewById(R.id.tv);
**EventBus.getDefault().register(this);**
btn.setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
startActivity(intent);
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onGetMessage(MessageWrap message) {
Log.d(TAG, "onGetMessage: " + message);
tv.setText(message.message);
}
.......
2.4 发布监听消息
public class MainActivity2 extends AppCompatActivity {
TextView tv2;
Button btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
tv2 = findViewById(R.id.tv2);
btn2 = findViewById(R.id.btn2);
btn2.setOnClickListener(v -> {
**EventBus.getDefault().post(MessageWrap.getInstance("Main2"));**
});
}
}
2.5 查看监听效果
三、黏性事件
一般使用的时候,都会和上面的demo类似的执行顺序,订阅者先订阅事件监听,被订阅者再发送消息,然后订阅者接受事件监听。如果想要被订阅者发送事件消息后,订阅者再订阅仍能收到消息,就需要用到eventBus的黏性事件。代码修改点如下:
订阅者订阅黏性事件:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
Button btn;
Button btn1;
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = findViewById(R.id.btnRegister);
tv = findViewById(R.id.tv);
btn1 = findViewById(R.id.btn1);
// EventBus.getDefault().register(this);
btn.setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
startActivity(intent);
});
btn1.setOnClickListener(v -> {
// 点击注册按钮注册黏性事件
EventBus.getDefault().register(this);
});
}
// 订阅黏性事件
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onGetMessage(MessageWrap message) {
Log.d(TAG, "onGetMessage: " + message);
tv.setText(message.message);
}
被订阅者发布黏性事件:
public class MainActivity2 extends AppCompatActivity {
TextView tv2;
Button btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
tv2 = findViewById(R.id.tv2);
btn2 = findViewById(R.id.btn2);
btn2.setOnClickListener(v -> {
// EventBus.getDefault().post(MessageWrap.getInstance("Main2"));
// 发布黏性事件
EventBus.getDefault().postSticky(MessageWrap.getInstance("Main2"));
});
}
}
log日志:
2.6 源码查看
2.6.1 发送黏性事件后
org.greenrobot.eventbus.EventBus#postSticky
public void postSticky(Object event) {
synchronized (stickyEvents) {
// stickyEvents集合存下黏性事件
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
org.greenrobot.eventbus.EventBus#post
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> **eventQueue** = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
// eventQueue不为空,会发送事件
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
2.6.2 订阅者订阅黏性事件
org.greenrobot.eventbus.EventBus#register
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
org.greenrobot.eventbus.EventBus#subscribe
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
......
if (subscriberMethod.sticky) {
if (eventInheritance) {
....
// 获取stickyEvents集合中的黏性事件数据,对照发送时存取数据
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}