What is IntentService
IntentService is a class that inherits from Service and handles asynchronous requests, but it has a higher priority than Service;
There is a worker thread in IntentService to handle time-consuming operations (implemented through HandlerThread and Handler);
The way to start IntentService is the same as that of traditional Service;
The difference is that after the task is executed, the IntentService will automatically stop without requiring us to manually control or stopSelf();
In addition, the IntentService can be started multiple times, and each time-consuming operation will be executed in the onHandleIntent callback method of the IntentService in the form of a work queue, and only one worker thread will be executed at a time, and the second one will be executed after the first one is executed;
How to use IntentService
-
IntentService is an abstract class that needs to be implemented concretely, first implement a MyIntentService;
-
Two methods must be implemented, one is the constructor and the other is the onHandleIntent method;
A string is passed in the constructor to represent the service name.
Some time-consuming operations of IntentService can be done in onHandleIntent.
In the onCreate method, although 7 IntentService instances are created cyclically, there is only one real instance.
Source code analysis of IntentService
Rough process:
The onCreate method that is executed first after the Service starts, creates HandlerThread and ServiceHandler in the onCreate method;
If you don't know HandlerThread, you can read this article
ServiceHandler inherits from Handler, which means that HandlerThread and Handler have been created in the onCreate method.
At the same time, it is noted that the Handler created by the Looper of the HandlerThread is used, that is to say, the looper of the Handler is associated with the MessageQueue in the child thread.
Then the Service executes to the onStartCommand method according to the life cycle, where a custom onStart method is added,
In the onStart method, the message is sent through the Handler, which is the ServiceHandler;
ServiceHandler executes onHandleIntent in its onHandleMessage method. From the above introduction, onHandleIntent is an abstract method that needs to be overwritten by itself.
After executing onHandleIntent, stopSelf will be called to close the service, that is, you don't need to close it manually.
Here stopSeft is parameterized, and the difference compared to the method without parameters is:
The one with parameters will not be executed immediately, and will wait for all messages to be processed before terminating the service.
Without arguments it will terminate immediately.
Why does onHandleMessage run in a child thread, that is why onHandleIntent can do time-consuming operations:
Because the looper of ServiceHandler corresponds to the looper of HandlerThread,
Generally, when a Handler is created in an Activity, the MainLooper is bound to the main thread, and onHandleMessage is executed in the main thread.
Similarly, ServiceHandler is bound to the looper of HandlerThread, and HandlerThread itself is a child thread.
Therefore, the onHandleMessage method of ServiceHandler runs on the child thread, which means that time-consuming operations can be performed in the onHandleIntent method.
The order in which messages are processed:
The same as Handler, Looper here takes tasks out of the message queue in order, which means that the background tasks of IntentServcie are also executed in order.
When there are multiple background tasks, these background tasks will also be executed sequentially.
The source code is just a few lines below.
public abstract class IntentService extends Service { private volatile Looper mServiceLooper; @UnsupportedAppUsage private volatile ServiceHandler mServiceHandler; private String mName; private boolean mRedelivery; 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); } } /** * 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; } /** * 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) { mRedelivery = enabled; } @Override public void onCreate() { // 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(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); } @Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } /** * 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 onDestroy() { mServiceLooper.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 @Nullable public IBinder onBind(Intent intent) { 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 should not call {@link #stopSelf}. * * @param intent The value passed to {@link * android.content.Context#startService(Intent)}. * This may be null if the service is being restarted after * its process has gone away; see * {@link android.app.Service#onStartCommand} * for details. */ @WorkerThread protected abstract void onHandleIntent(@Nullable Intent intent); }