当前位置:网站首页>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
边栏推荐
- Cesium knows the longitude and latitude of one point and the distance to find the longitude and latitude of another point
- Selenium Library
- mysql导入文件出现Data truncated for column ‘xxx’ at row 1的原因
- Data flow diagram, data dictionary
- Cesium 已知一点经纬度和距离求另一个点的经纬度
- Mrs offline data analysis: process OBS data through Flink job
- XML文件的解析操作
- 请问,我kafka 3个分区,flinksql 任务中 写了 join操作,,我怎么单独给join
- Is the compass stock software reliable? Is it safe to trade stocks?
- 用例图
猜你喜欢
OAuth 2.0 + JWT 保护API安全
最长上升子序列模型 AcWing 482. 合唱队形
Verilog implementation of a simple legv8 processor [4] [explanation of basic knowledge and module design of single cycle implementation]
The longest ascending subsequence model acwing 1014 Mountaineering
JS get the current time, month, day, year, and the uniapp location applet opens the map to select the location
UML state diagram
用例图
Take you to master the three-tier architecture (recommended Collection)
Docker deploy Oracle
【立体匹配论文阅读】【三】INTS
随机推荐
Regular expression integer positive integer some basic expressions
gvim【三】【_vimrc配置】
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
常用数字信号编码之反向不归零码码、曼彻斯特编码、差分曼彻斯特编码
oracle 非自动提交解决
How to check the ram and ROM usage of MCU through Keil
Arm cortex-a9, mcimx6u7cvm08ad processor application
MRS离线数据分析:通过Flink作业处理OBS数据
Excellent open source system recommendation of ThinkPHP framework
Csma/cd carrier monitoring multipoint access / collision detection protocol
设备故障预测机床故障提前预警机械设备振动监测机床故障预警CNC震动无线监控设备异常提前预警
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 state diagram
Pert diagram (engineering network diagram)
C # use TCP protocol to establish connection
Environment configuration
请问,我kafka 3个分区,flinksql 任务中 写了 join操作,,我怎么单独给join
Did login metamask
请问,在使用flink sql sink数据到kafka的时候出现执行成功,但是kafka里面没有数
低代码平台中的数据连接方式(下)