EventBus源碼分析
1、源碼分析要點
EventBus是觀察者模式,是一對多,一般源碼分析的重點在register方法上,分析的核心應在在消息隊列上PendingPostQueue
1、消息隊列
PendingPostQueue{
void enqueue(PendingPost pendingPost)//加入消息
PendingPost poll()//取出消息
}
2、處理消息核心 五種策略
interface Poster {
void enqueue(Subscription subscription, Object event);//加入消息
}
1、Poster消息隊列存取
class XXXPoster implements Runnable, Poster {
public void enqueue(Subscription subscription, Object event) {
//插入消息
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
//運行
eventBus.getExecutorService().execute(this);
}
@Override
public void run() {
//取出消息
PendingPost pendingPost = queue.poll();
//處理消息
eventBus.invokeSubscriber(pendingPost);
}
}
2、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);
}
}
}
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);
}
//注冊該類
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
}
找該類所有注解方法
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
subscriberMethods = findUsingReflection(subscriberClass);
return subscriberMethods;
}
//尋找注解實現(xiàn)
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) {
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()));
}
}
}
}
}
3、post放入消息流程
post(event)-->postSingleEvent()-->postSingleEventForEventType()-->postToSubscription()-->XXXPoster.enqueue(subscription, event)
1、通過event尋找注冊類
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
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);
}
}
通過event尋找該注冊類函數(shù)清單,發(fā)送
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//通過發(fā)送事件類型尋找注冊表
subscriptions = subscriptionsByEventType.get(eventClass);
}
//遍歷整個列表發(fā)送消息
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
//處理消息
postToSubscription(subscription, event, postingState.isMainThread);
}
return true;
}
return false;
}
4、普通post與postSticky區(qū)別
1、postSticky 緩存最新的一個事件
2、register后,postSticky 自動觸發(fā)一遍該類的緩存的事件
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
post(event);
}
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
if (subscriberMethod.sticky) {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
定制化RxBus
設計rxbus重點
1、調用方式與EventBus一致,降低使用成本
2、rxjava是觀察者模式,可以替換Eventbus消息隊列和處理消息的策略模式
3、支持線程安全
4、支持黏性事件