当前位置:网站首页>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
边栏推荐
- Excellent open source system recommendation of ThinkPHP framework
- 【网络安全】sql注入语法汇总
- 3D Detection: 3D Box和点云 快速可视化
- UML 顺序图(时序图)
- [network security] SQL injection syntax summary
- IP address home location query
- oracle 非自动提交解决
- Use day JS let time (displayed as minutes, hours, days, months, and so on)
- Beginner XML
- 请问指南针股票软件可靠吗?交易股票安全吗?
猜你喜欢

Vmware共享主机的有线网络IP地址

最长上升子序列模型 AcWing 482. 合唱队形

OAuth 2.0 + JWT protect API security

数据流图,数据字典

Equipment failure prediction machine failure early warning mechanical equipment vibration monitoring machine failure early warning CNC vibration wireless monitoring equipment abnormal early warning

AutoCAD - how to input angle dimensions and CAD diameter symbols greater than 180 degrees?

手把手教会:XML建模

The longest ascending subsequence model acwing 1012 Sister cities
![SSRF vulnerability file pseudo protocol [netding Cup 2018] fakebook1](/img/10/6de1ee8467b18ae03894a8d5ba95ff.png)
SSRF vulnerability file pseudo protocol [netding Cup 2018] fakebook1

Selenium库
随机推荐
Data flow diagram, data dictionary
Selenium Library
请问,在使用flink sql sink数据到kafka的时候出现执行成功,但是kafka里面没有数
Docker deploy Oracle
Navigation — 这么好用的导航框架你确定不来看看?
Excuse me, as shown in the figure, the python cloud function prompt uses the pymysql module. What's the matter?
Beginner XML
Es log error appreciation -limit of total fields
Excusez - moi, l'exécution a été réussie lors de l'utilisation des données de puits SQL Flink à Kafka, mais il n'y a pas de nombre dans Kafka
UML 顺序图(时序图)
The longest ascending subsequence model acwing 1014 Mountaineering
搜索框效果的实现【每日一题】
Advanced Mathematics - Chapter 8 differential calculus of multivariate functions 1
最长上升子序列模型 AcWing 1012. 友好城市
Search engine interface
参数关键字Final,Flags,Internal,映射关键字Internal
FCOS3D label assignment
用例图
LeetCode 648. 单词替换
请问指南针股票软件可靠吗?交易股票安全吗?