Eventbus for Android Source code Analysis

Source: Internet
Author: User
Tags eventbus

The example above explains Eventbus for Android and introduces the basic usage of Eventbus, this article introduces the implementation principle of Eventbus. The implementation of Eventbus is mainly around two functions register and post, respectively, described below.

1 Register (Object subscriber)

function
Registering a method with OnEvent beginning in subscriber
Code:

privatesynchronizedvoidregisterbooleanint priority) {    //构造出方法列表    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());    for (SubscriberMethod subscriberMethod : subscriberMethods) {        //注册每个方法        subscribe(subscriber, subscriberMethod, sticky, priority);    }}

Important Data Structures:
Subscribermethod: Parameter types for storage methods, threading models, and event events handling
The Subscriber function uses two map:subscriptionbyeventtype and typesbysubscriber to maintain the relationship between event subscribers and event types, as shown in the code

//must be called in synchronized blockPrivate void Subscribe(Object subscriber, Subscribermethod Subscribermethod,BooleanStickyintPriority) {class<?> EventType = Subscribermethod.eventtype;    copyonwritearraylist<subscription> subscriptions = Subscriptionsbyeventtype.get (EventType); Subscription newsubscription =NewSubscription (subscriber, Subscribermethod, priority);if(Subscriptions = =NULL) {subscriptions =NewCopyonwritearraylist<subscription> ();    Subscriptionsbyeventtype.put (EventType, subscriptions); }Else{if(Subscriptions.contains (newsubscription)) {Throw NewEventbusexception ("subscriber"+ subscriber.getclass () +"already registered to event"+ EventType); }    }//Starting with Eventbus 2.2 We enforced methods to is public (might change with annotations again)    //SubscriberMethod.method.setAccessible (TRUE);    intSize = Subscriptions.size (); for(inti =0; I <= size; i++) {//In priority order to insert in queue        if(i = = Size | | newsubscription.priority > Subscriptions.get (i). Priority) {Subscriptions.add (i, newsubscription); Break; }} list<class<?>> subscribedevents = Typesbysubscriber.get (subscriber);if(Subscribedevents = =NULL) {subscribedevents =NewArraylist<class<?>> ();    Typesbysubscriber.put (subscriber, subscribedevents);    } subscribedevents.add (EventType); ...}

This function is used in the copyonwritearraylist, next study.

2 post (Object event)

First look at the source:

 Public void Post(Object event) {//postingstate is a threadlocal variable that represents the process state of the sending eventPostingthreadstate postingstate = Currentpostingthreadstate.get ();//Add events to the queuelist<object> eventqueue = Postingstate.eventqueue; Eventqueue.add (event);//Send event    if(!postingstate.isposting)        {postingstate.ismainthread = Looper.getmainlooper () = = Looper.mylooper (); Postingstate.isposting =true;if(postingstate.canceled) {Throw NewEventbusexception ("Internal error. Abort state is not reset "); }Try{//Perform tasks in the queue             while(!eventqueue.isempty ()) {Postsingleevent (Eventqueue.remove (0), postingstate); }        }finally{postingstate.isposting =false; Postingstate.ismainthread =false; }    }}

Here is a class: Postingthreadstate, which is used to record the state of the current thread and the task queue, eventbus each task in the task queue with Postsingleevent, with the following code:

Private void postsingleevent(Object event, Postingthreadstate postingstate)throwsError {class<?> EventClass = Event.getclass ();BooleanSubscriptionfound =false;if(eventinheritance) {list<class<?>> eventtypes = lookupalleventtypes (EventClass);intCounttypes = Eventtypes.size ();//Get event type, including base class and interface         for(inth =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! = Subscriber Exceptionevent.class) {post (NewNosubscriberevent ( This, event)); }    }}

The main function of this function is to get the type of event, and if Eventinheritance is true, it gets the parent class of the event, and the interface, and then calls once for each type of Postsingleeventforeventtype (Object event, Postingthreadstate Postingstate, Class

Private Boolean Postsingleeventforeventtype(Object event, Postingthreadstate postingstate, class<?> EventClass) {copyonwritearraylist<subscription> subscriptions;synchronized( This) {//Get subscribers of the corresponding event type EventClassSubscriptions = Subscriptionsbyeventtype.get (EventClass); }if(Subscriptions! =NULL&&!subscriptions.isempty ()) { for(Subscription subscription:subscriptions) {//Initialize the status of the Send event threadPostingstate.event = event; Postingstate.subscription = subscription;Booleanaborted =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;}

Eventbus calls Posttosubscription (Subscription Subscription, Object event, Boolean ismainthread) after getting to the subscriber, method, and thread type that sent the event To notify the subscriber of event handling, the function code is as follows:

    Private void posttosubscription(Subscription Subscription, Object event,BooleanIsmainthread) {Switch(Subscription.subscriberMethod.threadMode) { CasePostthread://Call event handling events directlyInvokesubscriber (subscription, event); Break; CaseMainthread:if(Ismainthread) {The //Send thread is the primary thread and is called directlyInvokesubscriber (subscription, event); }Else{mainthreadposter.enqueue (subscription, event); } Break; CaseBackgroundthread:if(Ismainthread)                {backgroundposter.enqueue (subscription, event); }Else{the//send thread is a non-main path and is called directlyInvokesubscriber (subscription, event); } Break; CaseAsync:asyncPoster.enqueue (subscription, event); Break;default:Throw NewIllegalStateException ("Unknown thread mode:"+ Subscription.subscriberMethod.threadMode); }    }

This function uses different methods to inform subscribers based on different threading models, which are discussed separately below:

1 Postthread Model

Call Invokesubscriber (Subscription Subscription, Object event) directly, which uses the reflection principle to invoke the recipient's event-handling method

2 Mainthread Model

If the sending thread is the primary thread, the Subscriber event-handling method is invoked directly.
If the sending thread is not the primary thread, the event is sent to mainthreadposter for processing. The type of Mainthreadposter is Handlerposterand inherits from Handler. Handlerposter internally maintains a queue (pendingpostqueue) to access subscribers and corresponding event response methods. Each time the data is inserted into Handlerposter, Handlerposter sends a message informing handler to fetch the data from Pendingpostqueue and then invokes the subscriber's event-handling method, as follows:

voidEnqueue (Subscription Subscription, Object event) {Pendingpost pendingpost = Pendingpost.obtainpendingpost (subscriptio n, event);synchronized( This) {queue.enqueue (pendingpost);if(!handleractive) {handleractive =true;//If Looper is not running, send a message to notify it            if(!sendmessage (Obtainmessage ())) {Throw NewEventbusexception ("Could not send handler message"); }        }    }}@Override Public void Handlemessage(Message msg) {Booleanrescheduled =false;Try{Longstarted = Systemclock.uptimemillis (); while(true) {Pendingpost pendingpost = Queue.poll ();if(Pendingpost = =NULL) {synchronized( This) {//Check again, this time in synchronizedPendingpost = Queue.poll ();if(Pendingpost = =NULL) {handleractive =false;return; }                }            }//Take out the data in the queue, call the subscriber's methodEventbus.invokesubscriber (Pendingpost);LongTimeinmethod = Systemclock.uptimemillis ()-started;if(Timeinmethod >= Maxmillisinsidehandlemessage) {if(!sendmessage (Obtainmessage ())) {Throw NewEventbusexception ("Could not send handler message"); } rescheduled =true;return; }        }    }finally{handleractive = rescheduled; }}
3 Backgroundthread Model

If the sending thread is a non-primary thread, the event response function is called directly.
If the sending thread is the primary thread, the message is sent to Backgroundposter . The type of Backgroundposter is Backgroundposterand inherits from Runnable. And the Handlerposter type, the object also maintains an event queue:pendingpostequeue, each time the data is inserted, Backgroundposter will place itself in the thread pool of Eventbus to wait for dispatch, The complete code is as follows:

 Public void Enqueue(Subscription Subscription, Object event) {Pendingpost pendingpost = pendingpost.obtainpendingpost (subscription, event);synchronized( This) {queue.enqueue (pendingpost);//If the task in the thread pool is already running, return immediately,        if(!executorrunning) {executorrunning =true;//Get to Eventbus's thread poolEventbus.getexecutorservice (). Execute ( This); }    }}@Override Public void Run() {Try{Try{ while(true) {//Wait one second to remove the taskPendingpost pendingpost = Queue.poll ( +);if(Pendingpost = =NULL) {synchronized( This) {//Check again, this time in synchronizedPendingpost = 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

The model sends events directly to the asyncposter for processing. The type of Asyncposter is Asyncposterand inherits from Runnable. Unlike Backgroundposter, Asyncposter inserts the data into the queue and processes it directly into the thread pool, complete with the following code:

public  void  enqueue  (Subscription Subscription, Object event) {    Pendingpost pendingpost = pendingpost.obtainpendingpost (subscription, event);    Queue.enqueue (Pendingpost); Eventbus.getexecutorservice (). Execute (this );}  @Override  public  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 they join subscribers and events, they immediately put themselves into the thread pool, ensuring that each task is in a different thread. Instead, Backgroundposter will add tasks based on whether the Backgroundposter type of task in the thread pool is running in a thread pool. This ensures that all event-handling tasks in the Backgroundthread model are running in the same background thread.

Eventbus for Android Source code Analysis

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.