public void onEvent(MessageEvent event) {
log(event.message);
}
public void onEventMainThread(MessageEvent event) {
textField.setText(event.message);
}
public void onEventBackgroundThread(MessageEvent event){
saveToDisk(event.message);
}
什么是EventBus
EventBus是一个发布 / 订阅的事件总线。git地址:https://github.com/greenrobot/EventBus
笼统来讲EventBus可以分为三部分,发布者、订阅者、总线。订阅者通过总线订阅事件,发布者通过总线发布时间,因此订阅者就可以收到发布者发布的事件了。
如何使用EventBus
EventBus的使用也是很简单的,首先来看几个方法:
EventBus.getDefault().register(this);//订阅事件
EventBus.getDefault().post(object);//发布事件
EventBus.getDefault().unregister(this);//取消订阅
首先需要在oncreat里面注册EventBus,类似广播的注册,当然也需要在destory的时候取消注册。在需要发送也就是发布消息的地方调用post方法,注意里面的参数,然后在接受也就是事件处理的地方写几个方法即可。在3.0以前接收事件是这样的:
public void onEvent(MessageEvent event) {
log(event.message);
}
public void onEventMainThread(MessageEvent event) {
textField.setText(event.message);
}
public void onEventBackgroundThread(MessageEvent event){
saveToDisk(event.message);
}
方法必须以onEvent开头,但是3.0以后采用了注解的方式:
@Subscribe(threadMode = ThreadMode.MainThread) //在ui线程执行
public void onUserEvent(UserEvent event) {
}
@Subscribe(threadMode = ThreadMode.BackgroundThread) //在后台线程执行
public void onUserEvent(UserEvent event) {
}
@Subscribe(threadMode = ThreadMode.Async) //强制在后台执行
public void onUserEvent(UserEvent event) {
}
@Subscribe(threadMode = ThreadMode.PostThread) //默认方式, 在发送线程执行
public void onUserEvent(UserEvent event) {
}
举个栗子
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,third.class);
startActivity(intent);
}
// 3.接收方处理消息(处理数据)-- 主线程中执行
@Subscribe(threadMode = ThreadMode.MainThread)
public void onMainEventBus(MainMessage msg) {
Log.e(TAG, "onEventBus() handling message: " + Thread.currentThread().getName());
}
// 3.接收方处理消息(处理数据)-- 后台线程或子线程中执行
@Subscribe(threadMode = ThreadMode.BackgroundThread)
public void onBackgroundEventBus(BackgroundMessage msg) {
Log.e(TAG, "onEventBusBackground() handling message: " + Thread.currentThread().getName());
}
// 3.接收方处理消息(处理数据)-- 后台线程中执行
@Subscribe(threadMode = ThreadMode.Async)
public void onAsyncEventBus(AsyncMessage msg) {
Log.e(TAG, "onEventBusAsync() handling message: " + Thread.currentThread().getName());
}
// 3.接收方处理消息(处理数据)-- 和发送方在同一个线程
@Subscribe(threadMode = ThreadMode.PostThread)
public void onPostEventBus(PostMessage msg) {
Log.e(TAG, "onEventBusPost() handling message: " + Thread.currentThread().getName());
}
}
另一个负责发布事件的类:
public class OtherActivity extends Activity {
private final static String TAG = "EventBusTest";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.other_activity);
EventBus.getDefault().register(this);
}
// 3.接收方处理消息(处理数据)-- 主线程中执行
@Subscribe(threadMode = ThreadMode.MainThread)
public void onMainEventBus(MainMessage msg) {
Log.e(TAG, "onEventBus() handling message: " + Thread.currentThread().getName());
}
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;
}
}
}
用法还是很简单的,需要的可以下载demo:https://yunpan.cn/cSDavPcfvgLvY (提取码:9423)
简单源码解析
还是来简单看下源码,需要源码的可自行去git下载。
注册
register.java这个类是一个单例模式的类,按顺序我们先看他的register方法。
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
findSubscriberMethods方法作用就是遍历当前类里面的所有@Subscriber注解的方法。然后返回一个list,接着遍历List,调用subscribe方法订阅事件。
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (subscriberMethod.sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
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);
}
}
}
根据subscriberMethod.eventType,去subscriptionsByEventType去查找一个CopyOnWriteArrayList
顺便把我们的传入的参数封装成了一个:Subscription(subscriber, subscriberMethod, priority);
这里的subscriptionsByEventType是个Map,key:eventType ; value:CopyOnWriteArrayList
简单来讲这个方法就是把该类里面的所有@Subscriber注解的方法放进subscriptionsByEventType这个map里面,为后面事件做准备。
发送
/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
这个方法负责把事件发布到事件总线。currentPostingThreadState是一个ThreadLocal类型的,里面存储了PostingThreadState;PostingThreadState包含了一个eventQueue和一些标志位。把我们传入的event,保存到了当前线程中的一个变量PostingThreadState的eventQueue中。
根据isPosting为false的情况不断的调用postSingleEvent(eventQueue.remove(0), postingState)方法。
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
根据event的Class,去得到一个List<Class<?>>;其实就是得到event当前对象的Class,以及父类和接口的Class类型,遍历所有的Class,到subscriptionsByEventType去查找subscriptions这个map与register里面的map是同一个。遍历每个subscription,依次去调用postToSubscription(subscription, event, postingState.isMainThread);
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
这个就是根据注解里的threadMode去判断在哪个线程执行了。
case PostThread:
void invokeSubscriber(Subscription subscription, Object event) throws Error {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
}
直接在当前线程里面执行了。
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
首先去判断当前如果是UI线程,则直接调用;否则: mainThreadPoster.enqueue(subscription, event);把当前的方法加入到队列,然后直接通过handler去发送一个消息,在handler的handleMessage中,去执行我们的方法。说白了就是通过Handler去发送消息,然后执行的。
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
如果当前非UI线程,则直接调用;如果是UI线程,则将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用
executorService = Executors.newCachedThreadPool();。
case ASYNC:
asyncPoster.enqueue(subscription, event);
将任务加入到后台的一个队列,最终由Eventbus中的一个线程池去调用;线程池与BackgroundThread用的是同一个。
这么说BackgroundThread和Async有什么区别呢?
BackgroundThread中的任务,一个接着一个去调用,中间使用了一个布尔型变量handlerActive进行的控制。
Async则会动态控制并发。
取消
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
Subscribe
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
/**
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
*/
boolean sticky() default false;
/** Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s! */
int priority() default 0;
}
ThreadMode threadMode() default ThreadMode.POSTING;
也就是前面说道的执行方式,主线程还是其他线程,默认是当前线程。
boolean sticky() default false;
默认为false,时间立即执行。如果为true那表示事件事件不被马上处理。
int priority() default 0;
优先级,数字越大优先级越高,默认0。