当前位置:网站首页>Reading and understanding of eventbus source code
Reading and understanding of eventbus source code
2022-07-07 14:22:00 【LLAiden】
EventBus
Android Mainstream event delivery Library in , Simplify callbacks and thread operations in our code
EventBus introduce
implementation 'org.greenrobot:eventbus:3.2.0'
register
EventBus.getDefault().register(this);
Next, let's see how to register here
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
The first is a single example of a standard double lock hungry man , Let's look at
regsiter()
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
First of all to see
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
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 {
// Use in this class Subscribe Annotated functions are added to the cache
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
If there is no cache, it will execute
subscriberMethods = findUsingInfo(subscriberClass);Let's move on
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
// there findState.clazz It was passed in when we registered this
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
// Here for null Executive else Branch
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 {
// Continue to look at the source code here
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
// Get the function in this class in the signature
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) {
// Check whether this function has Subscribe annotation
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
// Get the parameters of this function class It's the event we deliver class
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
// Get what we set threadMode
ThreadMode threadMode = subscribeAnnotation.threadMode();
// Use this class Subscribe Annotated functions are added subscriberMethods in
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
}
}
}
}
It's over findSubscriberMethods() Let's keep looking subscribe() What have you done
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
// This object holds our subscription class and subscriber Annotated functions
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
// Put this type of Event Add to this Map
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) {
// This List In the above function, it has been stored in subscriptionsByEventType It's in
subscriptions.add(i, newSubscription);
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
// Which types of events this class focuses on are stored in typesBySubscriber
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
// Each registration will trigger a sticky Event Sending of
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);
}
}
}
Come here register I have finished reading , This is actually getting it for use Subscribe Annotated functions and related information ( Thread mode , priority , Whether it is a sticky event )
Event sending
Let's continue to look at the sending of events and how they are called , Take a look first EventBus.getDefaule().post()
public void post(Object event) {
// First, get the thread status , Because the default threadMode yes ThreadMode.POSTING
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()) {
// Send this event , Add this to the front list
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// Creating EventBus Whether this of the object is true Of
if (eventInheritance) {
// Here, the event class class as well as Object.class Save in eventTypes
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) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
synchronized (eventTypesCache) {
// Get the... In the cache first
List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
if (eventTypes == null) {
eventTypes = new ArrayList<>();
Class<?> clazz = eventClass;
while (clazz != null) {
// Our event class
eventTypes.add(clazz);
// This function will not execute internally without inheriting the interface
addInterfaces(eventTypes, clazz.getInterfaces());
// The second loop will add the parent of the event class to this list
clazz = clazz.getSuperclass();
}
// Add to cache , Go down and get it directly from the cache , It's better
eventTypesCache.put(eventClass, eventTypes);
}
// Now there are events class,Object.class, Because all classes implicitly inherit Object
return eventTypes;
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// stay register Called subscribe The function takes eventClass Events of type are stored in subscriptionsByEventType
// All this here if you register this type Event,subscriptions Not for null
// For details of this data storage, please see subscribe()
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted;
try {
// Here is the sending of events , Continue to look at the source code of this function
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;
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
//threadMode The default is POSTING
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
//Android Main thread execution
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
//mainThreadPoster When it was created, it was passed into Looper.getMainLooper()
// And use this Looper Created Handler object , So here is the use of Handler The mechanism is executed in the main thread
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
// Execute in the main thread first ,mainThreadPoster==null Execute in the sending thread
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
// Execute... In the process pool
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
// Asynchronous execution , Like and BACKGROUND There's no difference
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
// Here is the function to be executed , Use reflection to execute
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);
}
}
clazz = clazz.getSuperclass();It's worth noting , That is to say, we write a parameter of type Object Function of , And use Subscribe Annotation, then it can receive all our events
summary
- stay EventBus Instantiation time , Use the standard double lock mechanism to realize the singleton
- In execution
register()Function EventBus You will find that the modifier under this class is public, The number of parameters is 1, And use Subscribe Annotated functions , stay map For storage register()The function also sends sticky events , This is why we send sticky events first , Later, you can also receive the reason for the event by subscribing- stay
post()We will first find the event type in Map The corresponding function in , And use reflection to execute this function - EventBus Use in Handler Thread scheduling
边栏推荐
- requires php ~7.1 -&gt; your PHP version (7.0.18) does not satisfy that requirement
- Horizontal of libsgm_ path_ Interpretation of aggregation program
- 内部排序——插入排序
- IP and long integer interchange
- Excuse me, I have three partitions in Kafka, and the flinksql task has written the join operation. How can I give the join operation alone
- 用例图
- Huawei image address
- PERT图(工程网络图)
- How to check the ram and ROM usage of MCU through Keil
- oracle 触发器实现级联更新
猜你喜欢

The longest ascending subsequence model acwing 1014 Mountaineering

UML 顺序图(时序图)

UML sequence diagram (sequence diagram)

GAN发明者Ian Goodfellow正式加入DeepMind,任Research Scientist

Wired network IP address of VMware shared host

Transferring files between VMware and host

多商户商城系统功能拆解01讲-产品架构
![SSRF vulnerability file pseudo protocol [netding Cup 2018] fakebook1](/img/10/6de1ee8467b18ae03894a8d5ba95ff.png)
SSRF vulnerability file pseudo protocol [netding Cup 2018] fakebook1

常用数字信号编码之反向不归零码码、曼彻斯特编码、差分曼彻斯特编码

AI人才培育新思路,这场直播有你关心的
随机推荐
Excuse me, when using Flink SQL sink data to Kafka, the execution is successful, but there is no number in Kafka
mysql导入文件出现Data truncated for column ‘xxx’ at row 1的原因
【立体匹配论文阅读】【三】INTS
Cascading update with Oracle trigger
UML 状态图
call undefined function openssl_ cipher_ iv_ length
NDK beginner's study (1)
IP and long integer interchange
IP address home location query
FCOS3D label assignment
IP address home location query full version
Advanced Mathematics - Chapter 8 differential calculus of multivariate functions 1
属性关键字Aliases,Calculated,Cardinality,ClientName
Hands on Teaching: XML modeling
最长上升子序列模型 AcWing 1014. 登山
Huawei image address
课设之百万数据文档存取
Laravel5 call to undefined function openssl cipher iv length() 报错 PHP7开启OpenSSL扩展失败
Excuse me, why is it that there are no consumption messages in redis and they are all piled up in redis? Cerely is used.
Seven propagation behaviors of transactions