I am just a small Android dish, write technical documents just to summarize their knowledge learned in the recent, never dare to be a teacher, if there are some incorrect places please point out, thank you!

1. An overview of the

Service is used to perform tasks in the background, such as playing music, downloading files, uploading files, etc. Since a service runs on the main thread, it also has a time limit. If the processing time of a task in the main thread exceeds the time limit, the process experiences an “Application Not Responding”, or ANR, Application Not Responding. To avoid this, new threads are used in the service to handle tasks that may require more processing time.

Actually Android early for us to design a kind of more convenient service + thread model, is this article to tell IntentService, through which can be easily implemented using thread for time-consuming tasks in the service of processing.

This article will first show you the basic usage of IntentService and then explain the internals of IntentService.

2. Use of IntentService

Before we know how to use it, let’s take a look at what IntentService really is.

/**
 * IntentService is a base class for {@link Service}s that handle asynchronous
 * requests (expressed as {@link Intent}s) on demand.  Clients send requests
 * through {@link android.content.Context#startService(Intent)} calls; the
 * service is started as needed, handles each Intent in turn using a worker
 * thread, and stops itself when it runs out of work.
 *
 * <p>This "work queue processor" pattern is commonly used to offload tasks
 * from an application's main thread.  The IntentService class exists to
 * simplify this pattern and take care of the mechanics.  To use it, extend
 * IntentService and implement {@link #onHandleIntent(Intent)}.  IntentService
 * will receive the Intents, launch a worker thread, and stop the service as
 * appropriate.
 *
 * <p>All requests are handled on a single worker thread -- they may take as
 * long as necessary (and will not block the application's main loop), but
 * only one request will be processed at a time.
 */
public abstract class IntentService extends Service {... }Copy the code

I believe that you can easily understand the meaning of this statement, the small dish here is briefly summarized for you, such a long paragraph mainly explains two questions:

  1. IntentServiceWhat it is: A service that handles asynchronous requests has an internal worker thread in which all requests sent to the service are executed in sequence and the service is stopped automatically after all requests are processed.
  2. IntentServiceHow to use: ExtensionIntentServiceAnd implemented in its extension class, or subclassonHandleIntent(Intent)Interface in which the actual request processing takes place and the requests pass throughContext.startService(Intent)To send.

The Android SDK really serves as a model for all SDKS. It clearly tells you what it is and how to use it, and for more complex situations, gives examples directly in the statement.

Now that we know how to use IntentService, let’s use a small example:

2.1 the service side

The server side refers to the IntentService side, which receives and processes requests from the client.

public class TestIntentService extends IntentService {
    private static final String TAG = "TestIntentService";
    
    private static final String DEFAULT_NAME = "default_name";
    
    // In order to distinguish between different requests and facilitate the use of the calling side, different actions are directly defined.
    public static final String DOWNLOAD_ACTION = "com.test.intent.action.DOWNLOAD";
    public static final String UPLOAD_ACTION = "com.test.intent.action.UOLOAD";

    // To declare servcie in androidmanifest.xml, you must provide a no-argument constructor.
    public TestIntentService(a) {
        The constructor of IntentService needs to provide information about the name of a worker thread.
        super(DEFAULT_NAME);
    }

    @Override
    public void onCreate(a) {
        super.onCreate();
        Log.i(TAG, "onCreate");
    }

    @Override
    public void onDestroy(a) {
        super.onDestroy();
        Log.i(TAG, "onDestroy");
    }

    @Override
    public void onHandleIntent(Intent intent) {
        String action = intent.getAction();
        // Different processing is performed according to different request types.
        if (DOWNLOAD_ACTION.equals(action)) {
            try {
                Log.i(TAG, "onHandleIntent, start to download");
                Thread.sleep(30 * 1000);
            } catch(InterruptedException ie) { ie.printStackTrace(); }}else if (UPLOAD_ACTION.equals(action)) {
            try {
                Log.i(TAG, "onHandleIntent, start to upload");
                Thread.sleep(40 * 1000);
            } catch(InterruptedException ie) { ie.printStackTrace(); }}}}Copy the code

In this code, the request handler onHandleIntent(Intent) will perform different actions depending on the type of request it receives, sleeping for 30 seconds if it receives a “download” request and sleeping for 40 seconds if it receives an “upload” request.

After writing the service logic, do not forget to register it in androidmanifest.xml, otherwise it will not be able to use, the registration code is as follows:

<service android:name=".TestIntentService" />
Copy the code

It is simply registered without setting other related properties, such as intent-filter, because these are not directly relevant to the content of this article.

2.2 the client

The client is mainly used to send requests to the server.

// Send the download request
Intent downloadIntent = new Intent(this, TestIntentService.class);
downloadIntent.setAction(TestIntentService.DOWNLOAD_ACTION);
startService(downloadIntent);

// Send an upload request
Intent upIntent = new Intent(this, TestIntentService.class);
upIntent.setAction(TestIntentService.UPLOAD_ACTION);
startService(upIntent);
Copy the code

Now look at how IntentService responds to the “download” and “upload” requests:

02-27 12:58:23.100 24190 24190 I TestIntentService: onCreate 02-27 12:58:23.102 24190 24240 I TestIntentService: onCreate 02-27 12:58:23. OnHandleIntent, start to Download 02-27 12:58:53.107 24190 24240 I TestIntentService: OnHandleIntent, start to upload 02-27 12:59:33.115 24190 24190 I TestIntentService: onDestroyCopy the code

As you can see, when a “download” request is sent, the service is first created, and then the “download” request is processed, and then the “upload” request is received and processed after the first request. After all requests are processed, the service is destroyed automatically.

3. Principle of IntentService

IntentService can handle time-consuming tasks in a worker thread. What about IntentService? In this section, we analyze its source code to find out.

3.1 Creating a worker thread

Since IntentService’s function is to process tasks in a worker thread, let’s first look at how this worker thread is created.

public void onCreate(a) {
    // TODO: It would be nice to have an option to hold a partial wakelock
    // during processing, and to have a static startService(Context, Intent)
    // method that would launch the service & hand off a wakelock.

    super.onCreate();
    // Create a worker thread
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();
    
    // Is associated with a message loop within the worker thread
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}
Copy the code

When IntentService is first started, onCreate is called to perform some initialization operations:

  1. I created one firstHandlerThreadObject, which is the “worker thread” mentioned earlier. Everyone toHandlerandThreadWe all know that. So thisHandlerThreadWhat is it? Simply put, it is a thread with an internal message loop queue. We know that the default thread does not have an internal message loop queue, so we cannot use it directly within itHandler.AndroidFor ease of use, a queue containing a message loop is provided directlyHandlerThread.
  2. Make use of the createdHandlerThreadInternal message loop to create oneServiceHandlerObject so that its message handler functionhandleMessageIt will be executed in the corresponding thread.

3.2 Receiving and processing requests

Now that the worker thread has been created, it is time to consider how to receive and process the request from the client. The client sends the request through startService, and the onStartCommand callback is executed in the service lifecycle:

/**
 * You should not override this method for your IntentService. Instead,
 * override {@link #onHandleIntent}, which the system calls when the IntentService
 * receives a start request.
 * @see android.app.Service#onStartCommand
 */
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

@Override
public void onStart(@Nullable Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}
Copy the code

As you can see from this code, onStartCommand calls onStart directly, where the incoming request is received and processed by the mServiceHandler.

private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); }}Copy the code

In the handleMessage, the incoming request is actually handled with onHandleIntent, which is the processing logic we must implement in the process of using it.

3.3 Destroying worker Threads

The service is destroyed when all requests have been processed. As you can see from the handleMessage method above, stopSelf(msg.arg1) is called to try to stop the current service after processing the current request. “Try” because it may not actually stop the service. StopSelf (int)

/**
 * Old version of {@link #stopSelfResult} that doesn't return a result.
 *  
 * @see #stopSelfResult
 */
public final void stopSelf(int startId) {
    if (mActivityManager == null) {
        return;
    }
    try {
        mActivityManager.stopServiceToken(
                new ComponentName(this, mClassName), mToken, startId);
    } 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 particular 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}. 
 */
public final boolean stopSelfResult(int startId) {
    if (mActivityManager == null) {
        return false;
    }
    try {
        return mActivityManager.stopServiceToken(
                new ComponentName(this, mClassName), mToken, startId);
    } catch (RemoteException ex) {
    }
    return false;
}
Copy the code

The stopSelf(int) declaration mentions that this is the older version of stopSelfResult(int), the only difference being that there is no return value. StopSelfResult (int) will only be stopped if the last start of the current service was made by startId. IntentService = IntentService = IntentService = IntentService = IntentService = IntentService = IntentService = IntentService = IntentService = IntentService = IntentService After processing the second request, it is similar, except that after processing the third request, it tries to stop the service, and then it finds that the last startup was initiated by it and can stop the service.

When a service is stopped, onDestroy is called:

@Override
public void onDestroy(a) {
    mServiceLooper.quit();
}
Copy the code

At this point, the worker thread’s message loop is stopped and the thread exits.

4. To summarize

IntentService can accept requests sent by the user and process them sequentially in the worker thread. After the processing is completed, the user automatically exits the IntentService. However, since Android O has added more stringent control over background services, the background services contained in the current process cannot survive for a long time. IntentService also has some limitations on the use of IntentService. It is recommended to use the better JobIntentService.