当前位置:网站首页>Analysis of eventbus source code
Analysis of eventbus source code
2022-07-05 09:15:00 【Xu Jiajia 233】
summary
This article is suitable for EventBus have interest in , Or have been right EventBus Readers with certain use experience .
If the reader has not used it before EventBus, It is recommended to read the author's previous article :
register
Key logic :
Traverse the currently registered class , Get which used eventBus Method of annotation .
Register these methods to two HashMap in , Namely subscriptionsByEventType and typesBySubscriber. adopt synchronized Lock , To ensure thread safety .
subscriptionsByEventType:key yes eventType,value yes List
typesBySubscriber:key Is a registered object ,value yes ListMethod execution , Will judge whether there is stcky event , If any, it will trigger directly .
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
// Must be called in synchronized block
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);
} 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) {
subscriptions.add(i, newSubscription);
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
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);
}
}
}
post
Key logic :
- post The source code does two things , The first thing is to change the current event Add to eventQueue in . The second thing is to change the current thread to posting state .
- posting The status will be processed circularly eventQueue Medium event, Put it in the corresponding subscription In the implementation of .
– lookup subscription The process is : First find and event Related to the class , Then traverse these classes and their related subscription.
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
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 {
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 {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "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) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
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 boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
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;
}
postSticky
Key logic :
- And post comparison ,postSticky Will be will be event Add to stickyEvents This Map in .
- in front register The logic in has been mentioned , When a class is registered , Will judge whether there is stickyEvent, If any, it will trigger directly .
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
Multithreaded logic
Key logic :
- Finally trigger subscription when , Will be in postToSubscription Select the thread to execute .
- POSTING: Trigger directly on the current thread
- MAIN: If the current thread is the main thread , Then trigger directly . If you are not currently in the main thread , Then it will pass handler Throw it to the main thread to execute .
- BACKGROUND: If it is currently a child thread , Then trigger directly . If you are not currently in a child thread , Then it will be thrown to eventBus In the thread pool .
- ASYNC: Throw to eventBus In the thread pool .
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 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);
}
}
final class BackgroundPoster implements Runnable {
private final PendingPostQueue queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
边栏推荐
- 【PyTorch Bug】RuntimeError: Boolean value of Tensor with more than one value is ambiguous
- Introduction Guide to stereo vision (7): stereo matching
- AUTOSAR从入门到精通100讲(103)-dbc文件的格式以及创建详解
- Nodemon installation and use
- Mengxin summary of LIS (longest ascending subsequence) topics
- Array, date, string object method
- 2309. 兼具大小写的最好英文字母
- 我的一生.
- My life
- Codeworks round 639 (Div. 2) cute new problem solution
猜你喜欢

22-07-04 西安 尚好房-项目经验总结(01)

Install the CPU version of tensorflow+cuda+cudnn (ultra detailed)
![[code practice] [stereo matching series] Classic ad census: (4) cross domain cost aggregation](/img/d8/7291a5b14160600ba73810e6dd1eb5.jpg)
[code practice] [stereo matching series] Classic ad census: (4) cross domain cost aggregation

Kotlin introductory notes (II) a brief introduction to kotlin functions

Global configuration tabbar

优先级队列(堆)

一文详解图对比学习(GNN+CL)的一般流程和最新研究趋势

图神经网络+对比学习,下一步去哪?

Introduction Guide to stereo vision (2): key matrix (essential matrix, basic matrix, homography matrix)

Ros-11 common visualization tools
随机推荐
Shutter uses overlay to realize global pop-up
Codeworks round 638 (Div. 2) cute new problem solution
np. allclose
Nodemon installation and use
什么是防火墙?防火墙基础知识讲解
Luo Gu p3177 tree coloring [deeply understand the cycle sequence of knapsack on tree]
Solution to the problem of the 10th Programming Competition (synchronized competition) of Harbin University of technology "Colin Minglun Cup"
Talking about label smoothing technology
Use and programming method of ros-8 parameters
Summary and Reflection on issues related to seq2seq, attention and transformer in hands-on deep learning
Mengxin summary of LIS (longest ascending subsequence) topics
Alibaba cloud sends SMS verification code
The location search property gets the login user name
Meta tag details
Jenkins pipeline method (function) definition and call
My experience from technology to product manager
利用请求头开发多端应用
牛顿迭代法(解非线性方程)
STM32简易多级菜单(数组查表法)
高性能Spark_transformation性能