A brief analysis EventBus 3.0 source code

EvenBus can pass information between modules, reducing the use of the interface.


First, using the example of

<span style="font-size:18px;">public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EventBus.getDefault().register(this);

        testEventBus();

    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void getData(String result){
        Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
    }

    private void testEventBus(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5 * 1000);
                    
                    EventBus.getDefault().post("这是 EventBus 的测试");

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        EventBus.getDefault().unregister(this);
    }
}</span>


Second, registration 

EventBus.getDefault().regiser(this);

    EventBus responsible for external provided API.

(1) getDefault () obtained EventBus example, the use of volatile and singletons

<span style="font-size:18px;">   static volatile EventBus defaultInstance;
    /** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }</span>


new EventBus () object build time, using the model Builder

<span style="font-size:14px;">  public EventBus() {
        this(DEFAULT_BUILDER);
    }

    EventBus(EventBusBuilder builder) {
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);     // 一个主线程的 Handler
        backgroundPoster = new BackgroundPoster(this);   // Runnable
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }</span>


(2) register (Object subscriber) process

 EventBus There are several important members of the variables before we process analysis, take a look at

    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    private final Map<Object, List<Class<?>>> typesBySubscriber;

    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

subscripitonsByEventType and typesBySubcriber are HashMap, build new objects EventBus above initialization.

Which is subcriptionsByEventType eventType is key, Subcription lists for value; and typesBySubcriber based subscribers subcriber is key, the subscription list for the value of the event SubcribedEvents.


Subcription class has three member variables

    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    /**
     * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
     * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
     */
    volatile boolean active;

Which subcriber and typesBySubcriber the key link.

currentPostingThreadState is a ThreadLocal, storage PostingThreadState, for monitoring the entire post process, details of the ThreadLocal can see Renyu Gang's "Android developers explore art" book.


 Here is probably the whole process of registration:

Main line:


In  EventBus.java in

  public void register(Object subscriber) {
        // 返回一个 Class 类型的实例
        Class<?> subscriberClass = subscriber.getClass();  // 例如 com.yxhuang.mytestapplication.MainActivity
        //  获取订阅的方法, 内部最终时通过注解是方式获得订阅的方法
        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
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            // 如果已经注册过,则抛出异样,防止重复注册
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
            }
        }

        // 根据优先级添加到 CopyOnWriteArrayList 中
        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;
            }
        }

        // 添加到 Map<Object, List<Class<?>>>  typesBySubscriber
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        if (subscriberMethod.sticky) {  // 是否为粘性方法
            if (eventInheritance) {  // 默认是 false
                // 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();

                    // When using instanceof, you need to know the class of "B" at compile time. When using isAssignableFrom()
                    // it can be dynamic and change during runtime.
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

The whole process is quite simple

1, as a class subcriber key, pass into subcriberMethodFinder.findSubcriMethods (...) method, and get a list of all subscription methods;

2, call SUBCRIBE () method, a method corresponding to all subscribers and typesByScriber into subcriptionsByEventType, if the method is sticky subscription, the corresponding processing is performed.


Viscosity method of treatment, eventually calling checkPostStickEventToSubcriptions (...) method

    private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
            // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
            // --> Strange corner case, which we don't take care of here.
            // 根据不同的 ThreadMode 进行分发
            postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
        }
    }

Inside this last method called postToSubcription (...) method, distributing the corresponding subscription results, we have analyzed later in the post process. If the subscription is to be seen sticky, you do not need to call EventBus.post (...) method, after registration, it will self-distribute the results.


We look at how the registration process is to get all subscription methods.

After entering the subcriberMethodFinder.findSucriberMethod (...)

In  SucriberMethodFinder class

   // 是否忽略生成的 index
    private final boolean ignoreGeneratedIndex;   
    // 订阅缓存池
    private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
    // FindState 缓存池
    private static final int POOL_SIZE = 4;
    private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];

Which , FindState class method used to find the subscription process


SucriberMethodFinder.findSucriberMethod(...)

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        // 先从缓存中获取, METHOD_CACHE   是一个 CurrentHashMap
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {  // 是否忽略生成的 index 默认是 false
            // 使用反射获取单个类里面的订阅方法
            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 {
            // 放入缓存中并返回
            METHOD_CACHE.put(subscriberClass, subscriberMethods);
            return subscriberMethods;
        }
    }
1, ignoreGeneratedIndex default is false, only use the index generation, will be true, call findUsingReflection (...) method, the details can be viewed according to the back of recommended reading. Here we go findUsingInfo (...) this method;

2, the method for subscribing to look into the cache, and returns;


    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            // 获取订阅者的信息
            findState.subscriberInfo = getSubscriberInfo(findState);
            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 {
                // 利用反射查找自身的订阅方法
                findUsingReflectionInSingleClass(findState);
            }
            // 查找父类的订阅方法
            findState.moveToSuperclass();
        }
        // 返回所有的订阅方法,并释放掉 findState
        return getMethodsAndRelease(findState);
    }

  The subscriber's access to information

    private SubscriberInfo getSubscriberInfo(FindState findState) {
        // 获取父类订阅者的信息
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }
        // 默认是空的,是由使用了索引时,才会调用
        if (subscriberInfoIndexes != null) {  
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

1. calls getSubcriberInfo (...) method to get information about subscribers;

  2. Call findUsingRelectionInSingleClass (...), a subscription method to obtain reflection method;

  3. Find the subscription method of the parent class;

  4. relieve findState and returns a subscription method;


Here we look at FindState focus and how to use reflection to get a subscription method. Look at FindState

prepareFindState () and to getMethodsAndRelease () method of watching

private FindState prepareFindState() {
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                FindState state = FIND_STATE_POOL[i];
                if (state != null) {
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }
        }
        return new FindState();
    }

    private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        findState.recycle();
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                if (FIND_STATE_POOL[i] == null) {
                    FIND_STATE_POOL[i] = findState;
                    break;
                }
            }
        }
        return subscriberMethods;
    }

F IND_STATE_POOL there is a four FindState object caching pool;

In prepareFindState () method, was removed from a findState FIND_STATE_POOL buffer pool object and buffer pool location replace it with a null, then the call FindState.initForSubcriber (..) initialization findState; in getMethodsAndRelease (...) method the findState objects recycle () for processing, and then view the location FIND_STATE_POOL buffer pool is empty, this will make the process findState back into the buffer pool.

So that the entire process to achieve full utilization of findState object, the object is reduced because frequently generate too much and take up too much memory.


  SubcriberMethodFinder.findUsingRelectionInSingleClass(...) 方法

    private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        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;
        }
        for (Method method : methods) {
            //  返回一个用于描述构造器,方法或域的修饰符的整型数值。使用 Modifiers 类中的这个方法可以分析这个返回值。
            int modifiers = method.getModifiers();
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                // 返回一个用于描述参数类型的 Class 对象数组 (返回方法的参数)
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length == 1) {
                    // 获得给定类型的注解,如果没有这样的注解,则返回 null
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            // 获得 ThreadMod 类型
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            // 生成一个 SubscriberMethod 对象,放到列表中
                            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)) {
                // 方法不是 public 则抛出异样
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException(methodName +
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
        }
    }

1, Class.getDeclaredMethod () instead getMethod () method, because getDeclaredMethod () method and only returned to their own interfaces, and getMethod () returns not only themselves but also the method returns public methods inherited from the parent class such use getDeclaredMethod () method of the acquisition time can be saved;

2, we use the method when setting subscription Subcribe annotated class, and set the type ThreadMode

example:

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void getData(String result){
        Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
    }
and so

<span style="font-size:18px;">// 获得给定类型的注解,如果没有这样的注解,则返回 null
  Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);</span>
    You will get notes of this method;


3, after obtaining ThreadMode, put the list findState object member variable.


At this point, the entire registration process is basically complete.



Three, Post message procedure

PostingThreadState helper class used throughout the course of post

    /** For ThreadLocal, much faster to set (and get multiple values). */
    final static class PostingThreadState {
        // 存放 postEvent 事件列表
        final List<Object> eventQueue = new ArrayList<Object>();
        boolean isPosting;      // 是否处于 posting 状态
        boolean isMainThread;   //  是否为主线程
        Subscription subscription;      // 订阅信息
        Object event;
        boolean canceled;      // 是否被取消
    }

EventBus.post (...) method

  public void post(Object event) {
        // 中 ThreadLocal 中获取一个 PostingThreadState,  使用 ThreadLocal 传递对象,对整个 post 过程传递数据,不受不同线程的影响
        PostingThreadState postingState = currentPostingThreadState.get();      // currentPostingThreadState   是 ThreadLocal
        List<Object> eventQueue = postingState.eventQueue;   // ArrayList<>;
        eventQueue.add(event);   // 添加到列表中

        if (!postingState.isPosting) {
            // 是否为主线程
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            // post 的状态
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {
                    // post 一个 event 事件
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }
1, will post events stored in the queue, set some postingThreadState some of the content;

2, an event is removed from the queue and call postSingleEvent (...) method, the event handed out;

    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {  // 默认是 false,开启索引之后才会调用
            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 {
            // post 出去
            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));
            }
        }
    }
The index is not turned on, calls postSingleEventForEventType (...) method


 private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            // 从 map 中取出该类型的所以订阅者列表 subscriptions
            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;
    }
According evntType get this type of event all subscribers, and invokes postToSubcription (...) method will be distributed to all subscribers.


// 根据不同的 ThreadMode 进行分发
    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 {
                    // 如果不是在主线程,则利用 Handler , mainThreadPoster 是一个 主线程的 Handler
                    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);
        }
    }

According to different ThreadMode of a different method calls, these methods are relatively simple, not here Table


invokeSubscriber (...) method uses reflection, eventually calling subscription method

    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);
        }
    }


At this point, the process of post messages basically completed.



Fourth, the deregistration unregister (...)

Deregistration process is relatively simple, can be removed at the appropriate value in the Map of typesBySubcriber and subcriptionsByEventType

    public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);
        } else {
            Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

   /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        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--;
                }
            }
        }
    }


At this point a brief analysis EventBus entire process is over, learn more appropriate analysis of content, you can refer to the following references.


V. references

Click on the link to jump

1, EventBus 3.0 source code analysis 


2, EventBus 3.0 source code analysis


3, the old drivers to teach you "whirlwind" EventBus 3





发布了58 篇原创文章 · 获赞 20 · 访问量 9万+

Guess you like

Origin blog.csdn.net/yxhuang2008/article/details/52225586