Android IntentService usage and source code analysis
Introduction
Service is one of the four major Android components and plays a very important role in Android. Service is a working UI thread. When your application needs to download a file or play music, and is working in the background for a long time, there is no UI, you must use Service + Thread for implementation. Therefore, you need to implement a Thread working Thread in the Service to download files or play music. However, every time you need to write a Service + Thread on your own to process tasks that have been in the background for a long time without the UI interface, this is very troublesome, there is no need to build a Service + Thread framework every time to process tasks that have been in the background for a long time. Google engineers built an IntentService framework for developers to use.
Introduction to IntentService
IntentService is a basic class used to process Intent asynchronous task requests. When the client calls android. content. Context # startService (Intent) to send a request, the Service is started and a working thread is built inside it to process the Intent request. When the execution of a worker thread ends, the Service automatically stops. IntentService is an abstract class. You must implement a subclass to inherit it, and you must implement the abstract onHandleIntent method in IntentService to process asynchronous task requests.
IntentServic sample Client code
Public class ClientActivity extends AppCompatActivity {@ Override protected void onCreate (@ Nullable Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main);} // The client simultaneously sends two tasks to the IntentService server to execute public void send (View view) {Intent intent = new Intent (this, DownLoadService. class); intent. putExtra (key, 1); intent. putExtra (value, the first task1); startService (intent); Intent intent1 = new Intent (this, DownLoadService. class); intent1.putExtra (key, 2); intent1.putExtra (value, the second task2); startService (intent1 );}}
Simulate two asynchronous tasks for simultaneous requests and start the Service by carrying data through the Intent instance.
Service Client
Public class DownLoadService extends IntentService {public static final String TAG = DownLoadService; // rewrite the default constructor public DownLoadService () {super (DownLoadService );} // run @ Override protected void onHandleIntent (Intent intent) {int key = intent in the background thread. getIntExtra (key, 0); String value = intent. getStringExtra (value); switch (key) {case 1: // simulate time-consuming task 1 try {Thread. sleep (3*1000);} catch (InterruptedException e) {e. printStackTrace ();} break; case 2: // simulate time-consuming task 1 try {Thread. sleep (3*1000);} catch (InterruptedException e) {e. printStackTrace ();} break; default: break;} Log. e (TAG, the current time is: + System. currentTimeMillis ()/1000 + the Thread id is + Thread. currentThread (). getId () + the current task is + value );}}
The DownLoadService subclass inherits the IntentService class, and then implements the onHandleIntent abstract method to process the asynchronous tasks of Intent requests. In the DownLoadService class of the server, we have not created a Thread to execute asynchronous time-consuming task requests. All asynchronous time-consuming tasks are implemented in the onHandleIntent abstract method. The implication is that the IntentService class has already helped developers build an asynchronous task processor. You only need to implement the onHandleIntent abstract method to process asynchronous tasks, this makes it easier and convenient for developers to use IntentService to process Background asynchronous task requests. So how does IntentService build an asynchronous task processor? Let's look at the source code to find out.
IntentService source code analysis IntentService Constructor
/** * 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; }
Analysis: This constructor must be called in the subclass to create an IntentService object. The parameter name is used to define the name of the worker thread and is only used for tuning. We know that the Service life cycle starts from the onCreate method. Let's take a look at the IntentService # onCreate method.
IntentService # onCreate Method
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); }
Analysis: This method first creates a circular worker thread using the HandlerThread class, and then uses the logoff object in the worker thread as the parameter to create the ServiceHandler message executor. According to the source code analysis of Android HandlerThread in another blog, HandlerThread + Handler has built an asynchronous task processing mechanism with a message loop mechanism. Therefore, developers can encapsulate asynchronous tasks into messages and send them to the work thread for execution. The IntentService # onStartCommand method is executed in step 2 of the Service life cycle.
IntentService # onStartCommand Method
/** * 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(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; }
Analysis: In the IntentService subclass, you do not need to override this method. Then you need to override the onHandlerIntent method. The system will start calling this method when IntentService accepts a request. We can see that this method only calls the onStart method and traces the Code:
@Override public void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); }
Analysis: In this method, a message object msg is obtained through mServiceHandler, and startId is used as the message code of the message, the asynchronous task request intent is encapsulated into a message msg and sent to the mServiceHandler message executor for processing. Let's take a look at the implementation of 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); } }
Analysis: The implementation is relatively simple. ServiceHandler is an internal class of IntentService. In handlerMessage, The onHandlerIntent abstract method is called to process intent requests of asynchronous tasks, when the asynchronous task request ends, the stopSelf method is called to automatically end the IntentService service. Anyone who has read the blog Android HandlerThread source code analysis should know that the handleMessage method is called in the work thread. Therefore, the onHandlerIntent rewritten by our subclass is also implemented in the work thread. Let's take a look at the onHandlerIntent method:
/** * 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)}. */ protected abstract void onHandleIntent(Intent intent);
Analysis: This method is used to process intent asynchronous task requests and call this method in the work thread. Only one intent request can be processed at a time. When multiple intent requests exist at the same time, that is, when the client calls the Content # startService method multiple times to start the same service at the same time, other intent requests are temporarily suspended until the previous intent asynchronous task request is processed. After all intent requests are completed, IntentService calls stopSelf to stop the current service. That is, after the intent asynchronous task is processed, the corresponding IntentService is automatically destroyed, and the IntentService # onDestroy method is called:
@Override public void onDestroy() { mServiceLooper.quit(); }
In this method, call the quit method of the loose object in the HandlerThread working thread to exit the current loose loop and end the thread. End the current IntentService. At this point, the entire IntentService service has ended. Now you can use a flowchart to describe the entire process as follows:
The IntentService summary subclass must inherit the IntentService and implement the onHandlerIntent abstract method in it to process intent type task requests. The subclass must override the default constructor and call the constructor with parameters in the parent class in the constructor. The IntentService class uses HandlerThread + Handler to construct a background working thread with a message loop processing mechanism. The client only needs to call Content # startService (Intent) to put the Intent task request into the background work queue, the client does not need to pay attention to whether or not the service is finished, which is very suitable for one-time background tasks. For example, after the browser downloads the file and exits the current browser, the download task still exists in the background until the download file is complete and the service is automatically destroyed. As long as the current IntentService service is not destroyed, the client can place multiple Intent asynchronous task requests at the same time. The IntentService server side executes the Intent requests in the current background work queue sequentially, that is, only one Intent request can be executed at each time point until the Intent processing ends. The IntentService class uses HandlerThread + Handler to construct a single thread to process asynchronous tasks.