简单使用:
首先依赖eventbus
api ‘org.greenrobot:eventbus:3.2.0’
使用的方式很简单
在activity或者fragment中注册
EventBus.getDefault().register(this);
别忘记最后接触注册
EventBus.getDefault().unregister(this);
发送消息
EventBus.getDefault().post(msg)
接收消息
@Subscribe
public void getMsg(EventMessage msg){
}
这样eventbus就可以使用了接下来分析原理,按照上面的使用步骤挨个分析:首先分析注册的原理:
方法一
public void register(Object subscriber) {
1.获取订阅的class类型对象
Class<?> subscriberClass = subscriber.getClass();
2.获取当前class类对象所订阅的方法集合查看方法二
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
3.遍历所有的方法合集,订阅事件 查看方法三
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
方法二
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
首先先从METHOD_CACH中获取,如果有直接返回,不执行接下来的方法
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
这块如果自定义了EventBusBuilder,就走这块不是我们关注的重点
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;
}
}
接下来看这个方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
// FindState辅助我们查找订阅方法的类,
FindState findState = prepareFindState();
//将我们订阅的类传递进去
findState.initForSubscriber(subscriberClass);
//findState.clazz就是上面initForSubscriber传递进去的类
while (findState.clazz != null) {
//获取我们订阅类的订阅方法信息
findState.subscriberInfo = getSubscriberInfo(findState);
//第一次为空
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//直接看这里
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
// 将查找到的方法保存在了FindState实例的subscriberMethods集合中。然后使用subscriberMethods构建一个新的List<SubscriberMethod>并返回,最后释放掉findState
return getMethodsAndRelease(findState);
}
/**
* 作用:通过反射获取订阅方法的信息
*/
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
try {
methods = findState.clazz.getMethods();
} catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
String msg = "Could not inspect methods of " + findState.clazz.getName();
if (ignoreGeneratedIndex) {
msg += ". Please consider using EventBus annotation processor to avoid reflection.";
} else {
msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
}
throw new EventBusException(msg, error);
}
findState.skipSuperClasses = true;
}
//便利反射
for (Method method : methods) {
int modifiers = method.getModifiers();
//方法是public类型,但非abstract、static等
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) {
e // 获取该订阅方法上的第一个参数类型,也就是订阅的事件类型这个evnettype很重要,在之后会多次见到
Class<?> eventType = parameterTypes[0];
// checkAdd()方法用来判断FindState中是否已经添加过将该事件类型为key的键值对,没添加过则返回true
if (findState.checkAdd(method, eventType)) {
// 将该订阅方法,事件类型,线程模式,优先级,是否支持粘性事件等信息,封装成SubscriberMethod对象,并添加到findState中的subscriberMethods集合里
ThreadMode threadMode = subscribeAnnotation.threadMode();
findStated.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");
}
}
}
接下来方法三
/**
* 开始订阅
* subscriberMethod封装了当前方法的threadMode、eventType等
* eventType 订阅事件的参数class对象
* Subscription 以订阅类的class对象和SubscriberMethod 封装成的新对象
* 以eventType 为key,ArrayList<Subscription>为value的map
* typesBySubscriber以当前订阅的clas对象为key,list<eventType> 为值的map集合
* */
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//获取参数的class对象l类型
Class<?> eventType = subscriberMethod.eventType;
//订阅的类对象和subscriberMethod构造成新的对象
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//获取以eventType 为key的所有的Subscription对象
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
//没有创建,并添加subscriptionsByEventType
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//有看一下是否包含
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
// 添加上边创建的newSubscription对象到subscriptions中
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;
}
}
// typesBySubscriber也是一个HashMap,保存了以当前要订阅类的对象为keyd订阅类中参数类型的集合为value的键值对
// 和上面一样,根据key先判断,是否已经存储过了,如果已经存储过了,直接取出订注册类中订阅事件的方法的参数
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.pu t(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//判断s是否粘性事件
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);
}
}
}
简单总结下:
传入需要订阅类信息,根据反射获取类上的所有方法,遍历这些方法,取出其中的订阅方法(条件是,一个参数,权限为public,使用了Subscribe标签)将方法的信息封装成SubscriberMethod对象,并存入集合,然后再遍历这个集合,将出其中的SubscriberMethod对象以及当前订阅的class对象,合并成Subscription对象,然后根据eventtype类型,进行重新分类,存入map subscriptionsByEventType中(key 为eventtype, value 为List),再创建一个map typesBySubscriber, 以当前订阅的clas对象为key , list为value。 简单来说根据map typesBySubscriber就可以获取到当前订阅的页面所有参数类型的方法,然后再根据map subscriptionsByEventType以当前方法参数类型,获取到所有的Subscription对象,这样就建立了联系。
有了上面的注册接下来看解除注册
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
//获取当前订阅类页面所有的不同的eventtype的list,因为一个页面通常可能有很多订阅的事件参数也不一样
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
//便利这个list,解除订阅
for (Class<?> eventType : subscribedTypes) {
//方法四
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
/**
方法四
上面的方法已经获取到订阅页面所有的不同参数类型class对象然后根据这个对象,从subscriptionsByEventTypeq取出Subscription对象,判断Subscription的subscriber是否相同,相同移除。同样的参数类型也可能在多个页面注册,所有有多个,要找到当订阅对象的移除
*/
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
//获取该页面当前eventtpe所对应的list集合遍历
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--;
}
}
}
}
解除绑定,其实比较简单,主要就是运用注册时所产生的2个map, 先根据typesBySubscriber,也就是根据要解除绑定的注册类,找到这个类所拥有的所有订阅事件,然后遍历这些订阅事件,再根据这些订阅事件,在subscriptionsByEventType中找到,这个事件所对应的订阅方法的集合,再遍历集合,判断该订阅方法的注册类信息,是否是要解除绑定的注册类,如果是,移除该订阅方法信息,完成解除绑定。
接下来看post方法
public void post(Object event) {
//currentPostingThreadState就是个ThreadLocal可参考我的文章线 PostingThreadState 当前线程独有的,线程安全https://blog.csdn.net/m0_37777069/article/details/108768945
PostingThreadState postingState = currentPostingThreadState.get();
// 获取postingState里面存的一个队列
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;
}
}
}
//方法五
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
//对应的上面eventtype的类对象
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 {
//如果定义的发送消息事件没有弗雷直接走postSingleEventForEventType
//方法六
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
//如果没有匹配发送事件的类型,
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "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) {
//熟悉吧,根据参数类型获取Subscription对象,
subscriptions = subscriptionsByEventType.get(eventClass);
}
//不为空则遍历
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted;
try {
//方法七这时候就已经取到该事件接收的页面以及方法了
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
f } finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
//方法七根据订阅事件的消息模式来执行具体的事件 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 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);
}
}
//方法八直接通过反射执行相应的方法
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);
}
}
//方法九其实就是通过handler切换线程实现执行任务
public class HandlerPoster extends Handler implements Poster {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
这样基本一个事件从页面注册,到发送,整个流程就分析完了,总的来说还是很简单的,只要耐心看完,希望你有所收获