EventBus 3.1.1基础使用和原理浅析
1、简介
EventBus 是一个 Android 事件发布/订阅框架,通过解耦发布者和订阅者简化 Android 事件传递。
本文基于EventBus 3.1.1进行事件发布/订阅的使用和原理解析。
2、基础使用
①、添加依赖
compile 'org.greenrobot:eventbus:3.1.1'
②、注册
以在Activity中为例:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EventBus eb = EventBus.getDefault();
if (!eb.isRegistered(this)) {
eb.register(this);
}
}
③、反注册
如果注册了那么一定要反注册,否则会导致内存泄漏
以在Activity中为例:
@Override
protected void onDestroy() {
EventBus eb = EventBus.getDefault();
if (eb.isRegistered(this)) {
eb.unregister(this);
}
super.onDestroy();
}
④、添加接收方法
//@Subscribe 注入事件接收方法,如果一个activity或者fragment已经注册了,那么必须拥有至少一个事件接收方法
//threadMode = ThreadMode.MAIN 该方法的逻辑在主线程中执行,可更改为BackGround使逻辑在后台线程执行
//onEvent 方法名,可随意取,不同的activity中的方法名可以重复
//(Object Event) 唯一标示,假如此处写(User user),那么该方法只能接收User类型的消息
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(Object event) {
//TODO 接收到消息后的逻辑
}
⑤、发送消息
//这里的event的引用类型,就是onEvent接收方法里Object要明确指定的类
EventBus.getDefault().post(event);
3、原理浅析
①、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);
}
}
}
通过传入类获取class对象和subscriberMethods,这里着重看一下findSubscriberMethodsf()方法
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
这个方法中通过class对象获取了该class里所有的事件接收方法,并返回一个List,再来看一下SubscriberMethod这个类
public class SubscriberMethod {
final Method method;//Method对象,用于反射调用
final ThreadMode threadMode;//事件接收方法内逻辑执行在何种线程
final Class<?> eventType;//事件接收方法接受的形参引用类型
final int priority;//优先级
}
在register方法中通过
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
将所有的SubscriberMethod封装为Subscription对象存入subscriptionsByEventType这个Map集合中
②、post方法
/** 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 = isMainThread();
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;
}
}
}
可以看到该方法最终调用了这个方法来执行post
postSingleEvent(eventQueue.remove(0), postingState);
该方法通过调用来执行post
postSingleEventForEventType(event, postingState, eventClass);
下面看一看这个方法做了什么事情
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;
}
可以看到,这个方法通过eventClass从subscriptionsByEventType中获取了CopyOnWriteArrayList subscriptions集合,并通过循环的方式逐一调用postToSubscription方法来进行post,那么在看看postToSubscription方法
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 MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(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);
}
}
这个方法中,发现了invokeSubscriber方法,那么继续往下看
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
这里就很明显的可以看见,该方法使用Method对象利用反射直接调用订阅方法,实现了事件订阅。
③、性能问题
从以上原理浅析可以得出一个结论
1> 每一次register,EventBus就会把同一个EventType的订阅方法Method对象存入同一个List集合并放入Map中进行管理。
2> 每次post,都会通过EventType从Map中取出所有List,然后循环该List逐一调用反射方法进行消息发送。
3> 因为反射是比较耗费资源的,所以在定义事件的时候尽量避免无用的调用,也就是说尽量细化event。