EventBus for Android source code analysis

Source: Internet
Author: User

EventBus for Android source code analysis

The above example explains how EventBus for Android describes the basic usage of EventBus. This article introduces the implementation principle of EventBus. The implementation of EventBus mainly involves two functions.RegisterAndPost, Which is described below.

1 register (Object subscriber)

Function
Register the method starting with onEvent in subscriber
Code:

Private synchronized void register (Object subscriber, boolean sticky, int priority) {// constructs a List of methods
  
   
SubscriberMethods = subscription. Equals (subscriber. getClass (); for (SubscriberMethod subscriberMethod: subscriberMethods) {// register each method subscribe (subscriber, subscriberMethod, sticky, priority );}}
  

Important data structure:
SubscriberMethod: parameter types for storing methods, thread models, and Event processing
The subscriber function uses two maps: subscriptionByEventType and typesBySubscriber to maintain the relationship between the event subscriber and the event type, as shown in the code.

// Must be called in synchronized blockprivate void subscribe (Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {Class
  EventType = subscriberMethod. eventType; CopyOnWriteArrayList
  
   
Subscriptions = subscriptionsByEventType. get (eventType); subscriberMethod newsubcategory = new subscriber (subscriber, subscriberMethod, priority); if (subscriptions = null) {subscriptions = new CopyOnWriteArrayList
   
    
(); SubscriptionsByEventType. put (eventType, subscriptions);} else {if (subscriptions. contains (newsubception) {throw new EventBusException ("Subscriber" + subscriber. getClass () + "already registered to event" + eventType) ;}}// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) // subscriberMethod. method. setAccessible (true); int size = subscriptions. size (); for (int I = 0; I <= size; I ++) {// insert if (I = size | newsubtasks. priority> subscriptions. get (I ). priority) {subscriptions. add (I, newsubtasks); break;} List
    
     
> SubscribedEvents = typesBySubscriber. get (subscriber); if (subscribedEvents = null) {subscribedEvents = new ArrayList
     
      
> (); TypesBySubscriber. put (subscriber, subscribedEvents);} subscribedEvents. add (eventType );...}
     
    
   
  

CopyOnWriteArrayList is used in this function.

2 post (Object event)

First look at the source code:

Public void post (Object event) {// postingState is a ThreadLocal variable, indicating the Process status of the event to be sent: PostingThreadState postingState = currentPostingThreadState. get (); // Add an event to the queue ListEventQueue = postingState. eventQueue; eventQueue. add (event); // send Event if (! PostingState. isPosting) {postingState. isMainThread = logoff. getmainlogoff () = logoff. mylogoff (); postingState. isPosting = true; if (postingState. canceled) {throw new EventBusException ("Internal error. abort state was not reset ");} try {// execute the while (! EventQueue. isEmpty () {postSingleEvent (eventQueue. remove (0), postingState) ;}} finally {postingState. isPosting = false; postingState. isMainThread = false ;}}}

Here we encounter a class: PostingThreadState, which is used to record the status of the current thread and the task queue. EventBus uses postSingleEvent to process each task in the task queue. The Code is as follows:

Private void postSingleEvent (Object event, PostingThreadState postingState) throws Error {Class
  EventClass = event. getClass (); boolean subscriptionFound = false; if (eventInheritance) {List
  
   
> EventTypes = lookupAllEventTypes (eventClass); int countTypes = eventTypes. size (); // obtain the event type, including the base Class and interface 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 ));}}}
  

The main function of this function is to obtain the Event type. If eventInheritance is True, the parent class and interface of the Event will be obtained, and then the postSingleEventForEventType (Object event, postingThreadState postingState, Class

Private boolean postSingleEventForEventType (Object event, PostingThreadState postingState, Class
  EventClass) {CopyOnWriteArrayList
  
   
Subscriptions; synchronized (this) {// gets subscriptions = subscriptionsByEventType. get (eventClass);} if (subscriptions! = Null &&! Subscriptions. isEmpty () {for (subscribe subtions: subscriptions) {// initialize the status of the sending event thread postingState. event = event; postingState. subtasks = subtasks; boolean aborted = false; try {posttosubtasks (subtasks, event, postingState. isMainThread); aborted = postingState. canceled;} finally {postingState. event = null; postingState. subtasks = null; postingState. canceled = false;} if (aborted) {break;} return true;} return false ;}
  

After obtaining the subscriber, method, and thread type of the event sending, EventBus calls posttosubscribe (subscriber, Object event, boolean isMainThread) to notify the subscriber to process the event. The code of this function is as follows:

Private void posttosubscribe (subscribe, Object event, boolean isMainThread) {switch (subscribe. subscriberMethod. threadMode) {case PostThread: // directly call the Event to process the event invokeSubscriber (subscriber, Event); break; case MainThread: if (isMainThread) {// The sending thread is the main thread, directly call invokeSubscriber (subscriber, event);} else {mainThreadPoster. enqueue (subqueue, event);} break; case BackgroundThread: if (isMainThread) {backgroundPoster. enqueue (subthread, event);} else {// The sending thread is a non-main thread and directly calls invokeSubscriber (subscriber, event);} break; case Async: asyncPoster. enqueue (subqueue, event); break; default: throw new IllegalStateException ("Unknown thread mode:" + subqueue. subscriberMethod. threadMode );}}

This function uses different methods to notify subscribers based on different thread models. We will discuss the following:

1 PostThread Model

Directly call invokeSubscriber (subscriber, Object event). This method uses the reflection principle to call the receiver's event processing method.

2. MainThread Model

If the sending thread is the main thread, the subscriber event processing method is called directly.
If the sending thread is not the main thread, the event is sentMainThreadPoster. The mainThreadPoster type isHandlerPoster, Inherited from Handler. HandlerPoster internally maintains a queue (PendingPostQueue) To access the subscriber and corresponding event response methods. Every time data is inserted into HandlerPoster, HandlerPoster sends a message informing Handler to retrieve data from PendingPostQueue and then calls the subscriber's event processing method. The Code is as follows:

Void enqueue (subscribe, Object event) {PendingPost pendingPost = PendingPost. obtainPendingPost (subscribe, event); synchronized (this) {queue. enqueue (pendingPost); if (! HandlerActive) {handlerActive = true; // if logoff is not running, send a message to notify it if (! SendMessage (obtainMessage () {throw new EventBusException ("cocould not send handler message") ;}}@ Overridepublic void handleMessage (Message msg) {boolean rescheduled = false; try {long started = SystemClock. uptimeMillis (); while (true) {PendingPost pendingPost = queue. poll (); if (pendingPost = null) {synchronized (this) {// Check again, this time in synchronized pendingPost = queue. poll (); If (pendingPost = null) {handlerActive = false; return ;}}// retrieve the data in the queue and call the method eventBus of the subscriber. invokeSubscriber (pendingPost); long timeInMethod = SystemClock. uptimeMillis ()-started; if (timeInMethod> = maxMillisInsideHandleMessage) {if (! SendMessage (obtainMessage () {throw new EventBusException ("cocould not send handler message");} rescheduled = true; return ;}} finally {handlerActive = rescheduled ;}}
3. BackgroundThread Model

If the sending thread is not the main thread, the event response function is called directly.
If the sending thread is the main thread, the message is sentBackgroundPoster. The type of backgroundPoster isBackgroundPoster, Inherited from Runnable. And HandlerPoster type. This object also maintains an event queue:PendingPosteQueueEvery time data is inserted, BackgroundPoster puts itself into the EventBus thread pool for scheduling. The complete code is as follows:

Public void enqueue (subscribe, Object event) {PendingPost pendingPost = PendingPost. obtainPendingPost (subvertex, event); synchronized (this) {queue. enqueue (pendingPost); // if the task in the thread pool is already running, return immediately. if (! ExecutorRunning) {executorRunning = true; // gets EventBus's thread pool eventbus.getexecutorservice(cmd.exe cute (this) ;}}@ Overridepublic void run () {try {while (true) {// wait one second before obtaining the task 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 ;}}
4 Async Model

This model directly sends eventsAsyncPoster. The asyncPoster type isAsyncPoster, Inherited from Runnable. Unlike BackgroundPoster, AsyncPoster inserts data into the queue and directly puts itself into the thread pool for processing. The complete code is as follows:

public void enqueue(Subscription subscription, Object event) {    PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);    queue.enqueue(pendingPost);    eventBus.getExecutorService().execute(this);}@Overridepublic void run() {    PendingPost pendingPost = queue.poll();    if(pendingPost == null) {        throw new IllegalStateException("No pending post available");    }    eventBus.invokeSubscriber(pendingPost);}

The difference between Async and BackgroundPoster is that each time the former joins a subscriber and an event, it immediately puts itself into the thread pool to ensure that each task is in a different thread. BackgroundPoster checks whether a BackgroundPoster-type task in the thread pool is in the running state and processes the tasks in the thread pool, this ensures that all event processing tasks in the BackgroundThread model run in the same background thread.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.