EventBus使用与源码解析
- EventBus的基本原理
- EventBus的基本使用
- EventBus的源码分析
- 总结
EventBus的基本原理
EventBus模型图
从结构图可以看出,EventBus主要采用观察者模式
Publisher:事件的发送者。
EventBus:事件的中转中心,查找监听了相应事件的观察者,然后将事件传递过去
Subscriber:观察者,接受到监听事件的发生
Event:事件的载体
EventBus的基本使用
- 注册监听:
EventBus.getDefault().register(this) - 自定义一个Event
public class FirstEvent {
public FirstEvent(String message){
mMessage = message;
}
public String mMessage;
}
声明监听方法
@Subscribe
public void onEventMainThread(FirstEvent event){
Log.d(TAG, “onEventMainThread——->” + event.mMessage);
}@Subscribe
public void onEventBackgroundThread(FirstEvent event){
Log.d(TAG, “onEventBackgroundThread——->” + event.mMessage);
}@Subscribe
public void onEventAsync(FirstEvent event){
Log.d(TAG, “onEventAsync——->” + event.mMessage);
}通知
EventBus.getDefault().post(new FirstEvent(“发送消息”));
EventBus的使用就完成了,就是这么简单。
EventBus使用时注意事项:
- 注册了监听的的时候一定要在适当的时候反注册监听
EventBus.getDefault().unregister(this);
声明监听时间的时候一定要选择合适的方法
在上面的代码例子中,我们生命了三种监听方法:
@Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(FirstEvent event){ Log.d(TAG, "onEventMainThread------->" + event.mMessage); } @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(FirstEvent event){ Log.d(TAG, "onEventBackgroundThread------->" + event.mMessage); } @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(FirstEvent event){ Log.d(TAG, "onEventAsync------->" + event.mMessage); }
(1) onEventMainThread:表示该方法将在主线程中执行
(2) onEventBackgroundThread:表示该方法将在后台线程中执行
(3) onEventAsyn:表示将要创建一个线程来执行该方法
(4) 注意上面方法的注解,这这注解表示将在哪个线程中执行
如果对与一个Event,声明多个线程,则都会执行,如上例,三个方法都会监听到.
EventBus的源码分析
1.注解监听者
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
注意其中重要的一个方法:
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
这个方法就是找到你当前注册的这个观察者中所有添加@SubScrib这个注解的方法。我们看下其中一段关键代码:
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
上面的代码主要是找到这个观察者中所用添加@SubScrib注解的方法,然后判断这个方法是否是Public修饰的并且参数的个数为1,然后从该注解中获取被标注的方法将在哪个线程中执行也就是注解中的ThreadMode。
2.Post
发送事件,在EventBus中代码如下:
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;
}
}
}
上面一段代码的意思是在post事件的代码,主要的意思是将该事件加到队列里面,然后取出,然后再调用postSingleEvent(Object object, ThreadLocal threadlocal),这里用到ThreadLocal。
最后看下具体执行的方法:
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);
}
}
这里是直接调用反射来执行。
总结
- EventBus通过注解的方式注册监听的方法和参数
- EventBus默认在你调用Post的线程中执行
- 注册的方法名可以随便写,只要注解的ThreadMode写好就可以,但是为了可读性,最好不要随便命名方法
- 凡是注册了同一个Event的观察者,不管在注册到哪个线程,只要Post,都会执行。