IntentService source code analysis

Source: Internet
Author: User

Like HandlerThread, IntentService is a Helper class encapsulated by Android for us to simplify the development process. Next, when analyzing the source code

You will understand what is going on. IntentService is a basic Service class for on-demand processing of asynchronous requests expressed in Intent, essentially Android Service.

The client uses the Context # startService (Intent); Code to initiate a request. The Service is started only when it is not started, and

When all asynchronous requests are processed, IntentService automatically stops when all requests are processed, so you do not need to stop it explicitly. About how the client code is correct

For more information, see https://developer.android.com/training/run-background-service/create-service.html.

Next, let's take a look at the keyword field and ctor as we used:

Private volatile low.mserviceloaders; // both of them are associated with HandlerThread, but they do not understand why the volatile keyword private volatile ServiceHandler mServiceHandler is needed here; // It seems that they are only accessed in the UI thread, and there seems to be no concurrency problems... Private String mName; private boolean mRedelivery;/*** Creates an IntentService. invoked by your subclass's constructor. ** @ param name Used to name the worker thread, important only for debugging. */public IntentService (String name) {super (); mName = name ;}

Next let's look at interesting code:

Private final class ServiceHandler extends Handler {public ServiceHandler (loginloader) {super (login) ;}@ Override public void handleMessage (Message msg) {// based on our previous introduction to Handler, these codes are easy to understand onHandleIntent (Intent) msg. obj); // pay attention to this Template method. This is the place where the request is actually processed in our subclass: stopSelf (msg. arg1); // note that the stopSelf with parameters is called here, but not the stopSelf () without parameters.} // This is because IntentService does not exit after processing a request, all requests. }/*** Sets intent redelivery preferences. usually called from the constructor * with your preferred semantics. ** <p> If enabled is true, * {@ link # onStartCommand (Intent, int, int)} will return * {@ link Service # START_REDELIVER_INTENT }, so if this process dies before * {@ link # onHandleIntent (Intent)} returns, the process will be restarted * and the intent redelivered. if multiple Intents have been sent, only * the most recent one is guaranteed to be redelivered. ** <p> If enabled is false (the default), * {@ link # onStartCommand (Intent, int, int)} will return * {@ link Service # START_NOT_STICKY }, and if the process dies, the Intent * dies along with it. */public void setIntentRedelivery (boolean enabled) {// set whether to resend the Intent. Generally, set mRedelivery = enabled in ctor; // For details, please read the doc} @ Override public void onCreate () {// this method is called only when the service needs to be created for the first time. // TODO: it wocould be nice to have an option to hold a partial wakelock // during processing, and to have a static startService (Context, Intent) // method that wocould launch the service & hand off a wakelock. super. onCreate (); HandlerThread thread = new HandlerThread ("IntentService [" + mName + "]"); thread. start (); // start the next HandlerThread mserviceloading = thread that processes asynchronous client requests. getLooper (); mServiceHandler = new ServiceHandler (mserviceloader); // get the Handler associated with it, used to send it a message to be processed (client request )}

Next, let's look at two methods related to onStartXXX:

@ Override public void onStart (Intent intent, int startId) {// what it does is get a corresponding Message based on the parameter, Message msg = mServiceHandler. obtainMessage (); // send a Message. The Message is processed in ServiceHandler msg. arg1 = startId; // execute msg in the handleMessage method. obj = intent; // later we will analyze the mServiceHandler from startId. sendMessage (msg);}/*** You shocould not override this method for your IntentService. instead, * override {@ link # onHandl EIntent}, which the system callwhen the IntentService * has es a start request. * @ see android. app. service # onStartCommand */@ Override public int onStartCommand (Intent intent, int flags, int startId) {onStart (intent, startId); return mRedelivery? START_REDELIVER_INTENT: START_NOT_STICKY; // return different policy values based on mRedelivery}

Here we will explain the origins of int startId. First, let's talk about the code frameworks \ base \ services \ java \ com \ android \ server \ am \,

There are many classes under this directory that are very important to the Android internal mechanism (for example, "very famous" ANR dialog is here ). The two startId-related classes are

ServiceRecord and ActiveServices. Here we will look at the startId-related code in ServiceRecord, as follows:

Private int lastStartId; // identifier of most recent start request. public int getLastStartId () {return lastStartId;} public int makeNextStartId () {// call this method in ActiveServices lastStartId ++; if (lastStartId <1) {// Through the code, we can see that startId is a positive integer starting from 1, each time + 1 lastStartId = 1; // you can understand the number of client requests (that is, the number of startService calls)} return lastStartId ;}

This Code fully explains our long-standing confusions. For example, I have never understood why startId is used.

Next we will look at a set of stopXXX related methods:

/*** Stop the service, if it was previusly started. this is the same as * calling {@ link android. content. context # stopService} for this special service. ** @ see # stopSelfResult (int) */public final void stopSelf () {// The version with the Internal call parameter-1. This method stops service stopSelf (-1 );} /*** Old version of {@ link # stopSelfResult} that doesn't return a result. ** @ see # stopSelfResult */public final void stopSelf (int StartId) {// The parameter startId is either-1 or a positive integer starting from 1, only when it is equal to the last time we call if (mActivityManager = null) {// startService, when the startId value passed in onStartCommand is returned; // service will stop; otherwise, service will not stop. Service will automatically stop after processing} // all client requests. For example, if the client calls startService 10 times to try {// to send multiple requests, the service will stop only when startId = 10. mActivityManager. stopServiceToken (// Its onDestroy method will be called. In addition, because our requests are always processed in serial mode, new ComponentName (this, mClassName), mToken, startId) will never be created; // stopSelf (10) first and then stopSelf (9) will appear) this situation.} Catch (RemoteException ex) {}}/*** Stop the service if the most recent time it was started was * <var> startId </var>. this is the same as calling {@ link * android. content. context # stopService} for this particle service but allows you to * safely avoid stopping if there is a start request from a client that you * haven't yet seen in {@ link # onStart}. ** <p> <em> Be careful about ordering of yo Ur callto this function. </em>. * If you call this function with the most-recently specified ed ID before * you have called it for previously specified ed IDs, the service will be * immediately stopped anyway. if you may end up processing IDs out * of order (such as by dispatching them on separate threads), then you * are responsible for stopping them in the same order you have Ed them. </p> ** @ param s TartId The most recent start identifier already ed in {@ link * # onStart }. * @ return Returns true if the startId matches the last start request * and the service will be stopped, else false. ** @ see # stopSelf () */public final boolean stopSelfResult (int startId) {// This method is basically the same as above. I will not go into details about how stopServiceToken is implemented, if (mActivityManager = null) {// Let's see what is the difference between startId-1 and a positive integer. Return false;} try {return mActivityManager. stopServiceToken (new ComponentName (this, mClassName), mToken, startId);} catch (RemoteException ex) {} return false;} @ Override public void onDestroy () {// after all client requests are processed, the stop service is redirected to and logoff. Mservicelogs. quit ();}/*** Unless you provide binding for your service, you don't need to implement this * method, because the default implementation returns null. * @ see android. app. service # onBind */@ Override public IBinder onBind (Intent intent) {// The default implementation is sufficient when you are just a started service. Return null;}/*** This method is invoked on the worker thread with a request to process. * Only one Intent is processed at a time, but the processing happens on a * worker thread that runs independently from other application logic. * So, if this code takes a long time, it will hold up other requests to * the same IntentService, but it will not hold up anything else. * When all requests have been handled, the IntentService stops itself, * so you shoshould not call {@ link # stopSelf }. ** @ param intent The value passed to {@ link * android. content. context # startService (Intent )}. */protected abstract void onHandleIntent (Intent intent); // template method defined in handleMessage, that is, where the request processing logic occurs

As promised. Finally, let's take a look at what stopServiceToken has done. The Code is As follows:

Public boolean stopServiceToken (ComponentName className, IBinder token, // ActivityManagerService. method int startId) {synchronized (this) {return mServices. stopServiceTokenLocked (className, token, startId) ;}} boolean stopServiceTokenLocked (ComponentName className, IBinder token, // ActiveServices. method int startId) {if (DEBUG_SERVICE) Slog in java. v (TAG, "stopServiceToken:" + className + "" + t Oken + "startId =" + startId); ServiceRecord r = findServiceLocked (className, token, UserHandle. getCallingUserId (); if (r! = Null) {if (startId> = 0) {// pay attention to this judgment, as we have guessed. // Asked to only stop if done with all work. note that // to avoid leaks, we will take this as dropping all // start items up to and including this one. serviceRecord. startItem si = r. findDeliveredStart (startId, false); if (si! = Null) {while (r. deliveredStarts. size ()> 0) {ServiceRecord. startItem cur = r. deliveredStarts. remove (0); cur. removeUriPermissionsLocked (); if (cur = si) {break ;}} if (r. getLastStartId ()! = StartId) {// This code is the return false answer to all doubts; // if it is not the startId of the last request, it is returned directly and is not executed below ;} // This explains why the service cannot be stopped without the last startId. If (r. deliveredStarts. size ()> 0) {Slog. w (TAG, "stopServiceToken startId" + startId + "is last, but have" + r. deliveredStarts. size () + "remaining args") ;}} synchronized (r. stats. getBatteryStats () {r. stats. stopRunningLocked ();} r. startRequested = false; if (r. tracker! = Null) {r. tracker. setStarted (false, mAm. mProcessStats. getMemFactorLocked (), SystemClock. uptimeMillis ();} r. callStart = false; final long origId = Binder. clearCallingIdentity (); bringDownServiceIfNeededLocked (r, false, false); // code Binder that actually stops the service. restoreCallingIdentity (origId); return true;} return false ;}

So far, the IntentService-related code has been analyzed.

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.