当前位置:网站首页>Eventbus source code analysis
Eventbus source code analysis
2022-07-07 01:01:00 【yinianzhijian99】
First look at EventBus Use , It's simple , Example :
// register
EventBus.getDefault().register(this);
// Cancellation of registration
EventBus.getDefault().unregister(this);
// The main thread receives messages
@Subscribe(threadMode = ThreadMode.MAIN)
public void doEventBus(MsgEvent event){
// Processing logic ...
}
obtain EventBus example :
static volatile EventBus defaultInstance;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
Use the singleton mode , Get the same instance object
register() Method implementation :
public void register(Object subscriber) {
// First get the subscriber's class object
Class<?> subscriberClass = subscriber.getClass();
// adopt subscriberMethodFinder To find out what events subscribers subscribed to .
// Return to one SubscriberMethod Object's List, Class encapsulates subscription method information
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// subscribe
subscribe(subscriber, subscriberMethod);
}
}
}
SubscriberMethod class , Subscription method information , It encapsulates the method object to respond (method), Which thread will the response subscription be in the future (threadMode), The event type of subscription (eventType), Priority of subscription priority, And whether to receive stickiness sticky The event boolean value .
public class SubscriberMethod {
final Method method;
final ThreadMode threadMode;
final Class<?> eventType;
final int priority;
final boolean sticky;
}
Get subscription method information
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// Read from cache first
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
// Whether to ignore the generated by the annotator MyEventBusIndex class
if (ignoreGeneratedIndex) {
// Use reflection to get the subscription method information in the subscription class
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// Generated from the annotator MyEventBusIndex Class to get the subscription method information of the subscription class
subscriberMethods = findUsingInfo(subscriberClass);
}
// In obtaining subscriberMethods in the future ,
// If the subscriber does not exist @Subscribe Annotate and for public Subscription method of , An exception will be thrown .
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
// Save to cache map in
//METHOD_CACHE, It's a map aggregate , The key is class type
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
Focus on getting subscription information through reflection : Get all the methods through reflection , Traversal methods , Gets the parameter type array of the method , Get the annotation information of the method
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
//FindState Used to check and save subscription methods
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// Get subscription method information through reflection
findUsingReflectionInSingleClass(findState);
// Find the subscription method of the parent class
findState.moveToSuperclass();
}
// obtain findState Medium SubscriberMethod( That is, the subscription method List) And back to
return getMethodsAndRelease(findState);
}
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
// Get the method array through reflection
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
// Traverse Method
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
// Ensure that there must be only one event parameter
if (parameterTypes.length == 1) {
// Get comments
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
// Verify that the method is added
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
// Instantiation SubscriberMethod Object and add
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
EventBus There are two very important map aggregate
// subscriptionsByEventType aggregate ,key Is the event type , value yes Subscription object , Contains two properties , One is subscriber subscriber ( Reflection execution object ), One SubscriberMethod Annotate all attribute parameter values of the method
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
// typesBySubscriber aggregate key It's all subscribers ,value Is the parameter of the method in all subscribers class
private final Map<Object, List<Class<?>>> typesBySubscriber;
Event distribution resolution , See sending events post(event) The implementation of the , In fact, that is
Traverse subscriptionsByEventType, Find the matching method and call the method method.invoke() perform , Pay attention to switching threads .
public void post(Object event) {
// Gets the current thread's postingState
PostingThreadState postingState = currentPostingThreadState.get();
// Get the event queue of the current thread
List<Object> eventQueue = postingState.eventQueue;
// Add this event to the current event queue for distribution
eventQueue.add(event);
if (!postingState.isPosting) {
// Determine whether it is in the main thread post
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()) {
// Distribute events
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
Deregistration implementation :
public synchronized void unregister(Object subscriber) {
// Get the event types of all subscribers
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
// Remove subscribers from the subscriber collection of event types
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
// Get all subscribers of the event type
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
// Traverse subscriber collection , Remove the cancelled subscriber
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
To sum up EventBus How it works
Subscription logic
1. First use register() Method to register a subscriber
2. Methods to get all subscriptions of this subscriber
3. According to the event types of all subscriptions of this subscriber , Store subscribers to each event with event type key Take all subscribers as values Of map Collection
4. Then add the subscription event to the subscriber key Take all subscription events of subscribers as values Of map Collection
5. If it is a subscriber who has subscribed to sticky events , Get the previously sent sticky events from the sticky event buffer , Respond to these sticky events .
Event sending logic
1. First, get the event queue of the current thread
2. Add the event to be sent to the event queue
3. Get all subscribers according to the sending event type
4. According to the execution mode of the response method , Execute the subscriber's subscription method through reflection in the corresponding thread
Cancel logic
1. First, through unregister Method to get the subscriber to cancel
2. Get all subscription event types of the subscriber
3. Traversal event types , Get all subscriber sets according to each event type , And delete the subscriber from the collection
4. Take the subscriber from step 2 Remove from the set of
边栏推荐
- OSPF configuration command of Huawei equipment
- JS+SVG爱心扩散动画js特效
- 【JVM调优实战100例】05——方法区调优实战(下)
- New feature of Oracle 19C: automatic DML redirection of ADG, enhanced read-write separation -- ADG_ REDIRECT_ DML
- Advanced learning of MySQL -- Fundamentals -- four characteristics of transactions
- 【YoloV5 6.0|6.1 部署 TensorRT到torchserve】环境搭建|模型转换|engine模型部署(详细的packet文件编写方法)
- 随时随地查看远程试验数据与记录——IPEhub2与IPEmotion APP
- Service asynchronous communication
- UI控件Telerik UI for WinForms新主题——VS2022启发式主题
- 深度学习框架TF安装
猜你喜欢
《安富莱嵌入式周报》第272期:2022.06.27--2022.07.03
Stm32f407 ------- SPI communication
New feature of Oracle 19C: automatic DML redirection of ADG, enhanced read-write separation -- ADG_ REDIRECT_ DML
界面控件DevExpress WinForms皮肤编辑器的这个补丁,你了解了吗?
省市区三级坐标边界数据csv转JSON
Provincial and urban level three coordinate boundary data CSV to JSON
详解OpenCV的矩阵规范化函数normalize()【范围化矩阵的范数或值范围(归一化处理)】,并附NORM_MINMAX情况下的示例代码
5种不同的代码相似性检测,以及代码相似性检测的发展趋势
ActiveReportsJS 3.1中文版|||ActiveReportsJS 3.1英文版
随时随地查看远程试验数据与记录——IPEhub2与IPEmotion APP
随机推荐
Data processing of deep learning
[batch dos-cmd command - summary and summary] - jump, cycle, condition commands (goto, errorlevel, if, for [read, segment, extract string]), CMD command error summary, CMD error
Advanced learning of MySQL -- basics -- multi table query -- inner join
《安富莱嵌入式周报》第272期:2022.06.27--2022.07.03
Chapter II proxy and cookies of urllib Library
C9 colleges and universities, doctoral students make a statement of nature!
ZYNQ移植uCOSIII
第五篇,STM32系统定时器和通用定时器编程
ZABBIX 5.0: automatically monitor Alibaba cloud RDS through LLD
深度学习之数据处理
[牛客] B-完全平方数
How to get started and improve test development?
mongodb客户端操作(MongoRepository)
Dell筆記本周期性閃屏故障
ActiveReportsJS 3.1中文版|||ActiveReportsJS 3.1英文版
Dell笔记本周期性闪屏故障
. Bytecode structure of class file
Threejs image deformation enlarge full screen animation JS special effect
Activereportsjs 3.1 Chinese version | | | activereportsjs 3.1 English version
深度学习之环境配置 jupyter notebook