Use of IntentService in Android and its source code parsing; androidintent source code
Why do we need IntentService?
In Android, IntentService is inherited from the Service class. Before we discuss IntentService, we should first consider the features of the Service: the Service callback method (onCreate, onStartCommand, onBind, onDestroy) all are running in the main thread. After we start the Service through startService, We need to write code in the onStartCommand method of the Service to complete the work, but onStartCommand is run in the main thread, if we need to perform some time-consuming operations such as network requests or I/O here, the main thread UI will be blocked and no response will occur, resulting in ANR phenomenon. To solve this problem, the best way is to create a new thread in onStartCommand and put the time-consuming code into this new thread for execution. You can refer to the previous article "Examples of batch download by using startService in Android". In this article, a new thread is enabled in onStartCommand as the working thread to execute network requests, so this will not block the main thread. Therefore, creating a Service with a working thread is a common requirement (because the working thread does not block the main thread). Therefore, to simplify the development of a Service with a working thread, Android, android has developed an additional class called IntentService.
IntentService features
IntentService has the following features:
1.IntentService comes with a working threadWhen our Service needs to do some work that may block the main thread, you can consider using IntentService.
2.The actual work we need to do is put into the onHandleIntent of IntentService and return to the method.When IntentService is started through startService (intent), the Android Framework calls back its onHandleIntent method and passes the intent into the method. In this way, we can perform actual work according to intent,OnHandleIntent runs in the work thread held by IntentService, rather than the main thread.
3. When IntentService is started multiple times through startService, multiple jobs are generated. Because IntentService only holds one working thread, onHandleIntent can process only one job at a time. How does IntentService handle multiple jobs? The processing method is one-by-one, that is, one-by-one processing. First, intent1 is passed into onHandleIntent to complete job1, and then intent2 is passed into onHandleIntent to complete job2... This is until all jobs are completed, so weIntentService cannot execute multiple jobs in parallel and can only be completed one by one in sequence. When all jobs are completed, IntentService is destroyed and the onDestroy callback method is executed..
How to Use IntentService?
In the document "Examples of batch download via startService for Android", we demonstrate how to batch download articles through the Service. Now we want to demonstrate how to batch download articles in this article, however, IntentService is used to complete this task.
The system interface is as follows:
The interface is very simple. Just click "batch download articles" and start DownloadService with the button on the Activity.
DownloadService is a service used to download blog posts on CSDN. The Code is as follows:
Package com. ispring. startservicedemo; import android. app. intentService; import android. content. intent; import android. util. log; import java. io. IOException; import java. io. inputStream; import java.net. httpURLConnection; import java.net. malformedURLException; import java.net. URL; public class DownloadIntentService extends IntentService {public DownloadIntentService () {super ("Download"); Log. I ("DemoLog", "Dow NloadIntentService constructor, Thread: "+ Thread. currentThread (). getName () ;}@ Override public void onCreate () {super. onCreate (); Log. I ("DemoLog", "DownloadIntentService-> onCreate, Thread:" + Thread. currentThread (). getName () ;}@ Override public int onStartCommand (Intent intent, int flags, int startId) {Log. I ("DemoLog", "DownloadIntentService-> onStartCommand, Thread:" + Thread. currentThread (). g EtName () + ", startId:" + startId); return super. onStartCommand (intent, flags, startId) ;}@ Override protected void onHandleIntent (Intent intent) {HttpURLConnection conn = null; InputStream is = null; String blogUrl = intent. getStringExtra ("url"); String blogName = intent. getStringExtra ("name"); try {// download the specified file URL = new url (blogUrl); conn = (HttpURLConnection) URL. openConnection (); if (conn! = Null) {// here we get the input stream of the downloaded article, you can write it to the memory card as a file or // read the extracted text and display it in the App is = conn. getInputStream () ;}} catch (MalformedURLException e) {e. printStackTrace ();} catch (IOException e) {e. printStackTrace ();} finally {if (conn! = Null) {conn. disconnect () ;}} Log. I ("DemoLog", "DownloadIntentService-> onHandleIntent, Thread:" + Thread. currentThread (). getName () + "," + blogName + "" downloaded ");} @ Override public void onDestroy () {super. onDestroy (); Log. I ("DemoLog", "DownloadIntentService-> onDestroy, Thread:" + Thread. currentThread (). getName ());}}
The DownloadActivity code is as follows:
Package com. ispring. startservicedemo; import android. app. activity; import android. content. intent; import android. OS. bundle; import android. view. view; import android. widget. button; import java. util. arrayList; import java. util. hashMap; import java. util. iterator; import java. util. list; import java. util. map; public class DownloadActivity extends Activity implements Button. onClickListener {@ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_download) ;}@ Override public void onClick (View v) {List <String> list = new ArrayList <> (); list. add ("use of Handler in Android; http://blog.csdn.net/iispring/article/details/47115879"); list. add ("in-depth source code parsing in Android Handler, Message, MessageQueue, logoff; http://blog.csdn.net/iispring/article/details/47180325"); list. add ("View method summary in the main thread UI updated in the new Android thread; http://blog.csdn.net/iispring/article/details/47300819"); list. add ("Android HandlerThread usage and principles; http://blog.csdn.net/iispring/article/details/47320407"); list. add ("the quit method and the quitSafely method; http://blog.csdn.net/iispring/article/details/47622705"); Iterator iterator = list. iterator (); while (iterator. hasNext () {String str = (String) iterator. next (); String [] splits = str. split (";"); String name = splits [0]; String url = splits [1]; Intent intent = new Intent (this, DownloadIntentService. class); intent. putExtra ("name", name); intent. putExtra ("url", url); // start IntentService startService (intent );}}}
When we click the "batch download articles" button, we call the startService method of Activity multiple times. In this method, the intent parameter stores the article name and the url of the article, since we have called the startService method multiple times, we will download articles in batches.
After you click the button, the console runs as follows:
Through the above output, we can find that the onCreate, onStartCommand, and onDestroy callback methods of DownloadIntentService are all running in the main thread, while onHandleIntent is running in the IntentService [Download] of the working thread, this verifies the first and second features of the IntentService we mentioned above.
Through the above output results, we will also find that after we call startService (intent) five times in a row, onStartCommand is called five times in turn, and thenRunThe onHandleIntent is completed five times in sequence. When the last job is completed, that is, after the last onHandleIntent call is completed, the entire IntentService is completed and the onDestroy callback method is executed, intentService destruction.
Working Principle and source code analysis of IntentService
We have already introduced the features of IntentService and how to use it, so you may wonder how Android transfers the scheduling intent to onHandleIntent to complete the work. In fact, the working principle of IntentService is very simple, convert intent to Message and put it in the Message queue. Then, let Handler extract the Message from it and process it in sequence.
The source code of IntentService is as follows:
Package android. app; import android. content. intent; import android. OS. handler; import android. OS. handlerThread; import android. OS. IBinder; import android. OS. logoff; import android. OS. message; public abstract class IntentService extends Service {private volatile low.mserviceloader; private volatile ServiceHandler mServiceHandler; private String mName; private boolean mRedelivery; private final class Se RviceHandler extends Handler {public ServiceHandler (Looper loader) {super (logoff) ;}@ Override public void handleMessage (Message msg) {// call onHandleIntent in the work thread, make sure that onHandleIntent does not block the main thread onHandleIntent (Intent) msg. obj); // After onHandleIntent is executed, we need to call stopSelf (startId) to declare that a job has completed. // when all jobs are completed, Android calls back the onDestroy method, destroy IntentService stopSelf (msg. arg1) ;}} public IntentService (String name) {// name here Will be used as thread name super (); mName = name;} public void setIntentRedelivery (boolean enabled) {mRedelivery = enabled;} @ Override public void onCreate () {super. onCreate (); // create a HandlerThread and use mName as the thread name. HandlerThread is the working thread of IntentService. HandlerThread thread = new HandlerThread ("IntentService [" + mName + "]"); thread. start (); mserviceloading = thread. getLooper (); // pass the logoff object bound to the created HandlerThread to ServiceHandl Er, // then the Handler we created is bound to HandlerThread through the Message Queue mServiceHandler = new ServiceHandler (mserviceloader);} @ Override public void onStart (Intent intent, int startId) {// create a Message object in this method and use intent as the obj parameter of the Message. // the Message and Intent are associated with Message msg = mServiceHandler. obtainMessage (); msg. arg1 = startId; msg. obj = intent; // send the Message associated with the Intent information to Handler mServiceHandler. sendMessage (msg) ;}@ Override pub Lic int onStartCommand (Intent intent, int flags, int startId) {// IntentService overwrites the onStartCommand callback method: calls the onStart callback method internally. // when we inherit the IntentService, this method should not be overwritten. Even if it is overwritten, we should call super. onStartCommand () onStart (intent, startId); return mRedelivery? START_REDELIVER_INTENT: START_NOT_STICKY;} @ Override public void onDestroy () {// The Handler quit method is called in the onDestroy method, which terminates the message loop mserviceloading. quit () ;}@ Override public IBinder onBind (Intent intent) {return null;} protected abstract void onHandleIntent (Intent intent );}
I have added a lot of comments to the above Code. I believe you can understand how IntentService works by Directly Reading the code.
IntentService inherits from the Service class, And IntentService overrides the onCreate, onStartCommand, onStart, and onDestroy callback methods, and IntentService also adds an onHandleIntent callback method. Next we will explain the functions of these methods in IntentService in sequence.
OnCreate: In the onCreate callback method, use mName as the thread name to create HandlerThread. HandlerThread is the worker thread of IntentService. After the start method is executed, HandlerThread is associated with the message queue and logoff, and the message queue starts to loop.
OnStartCommand: IntentService overwrites the onStartCommand callback method: calls the onStart callback method internally.
OnStart: Create a Message object in the onStart method and use intent as the obj parameter of the Message, so that the Message is associated with Intent, then, the Message associated with the Intent information is sent to the Handler through the sendMessage method of Handler.
OnHandleIntent: When the onStart method puts the Message into the Message Queue associated with Handler by using the sendMessage method, The logoff object associated with Handler retrieves a Message from the Message queue, then, pass it into the handleMessage method of Handler. In the handleMessage method, first obtain the original Intent object through the obj of the Message, and then pass it as a parameter to the onHandleIntent Method for execution. The handleMessage method runs in HandlerThread, so onHandleIntent is also running in the working thread. After onHandleIntent is executed, we need to call stopSelf (startId) to declare that a job is complete. When all jobs are completed, Android calls back the onDestroy method to destroy IntentService.
OnDestroy: When all jobs are completed, the Service will destroy and execute its onDestroy callback method. In this method, the quit method of Handler is called, which terminates the message loop.
Summary
IntentService can complete the work in the working thread without blocking the main thread. However, IntentService cannot process multiple jobs in parallel and can only process jobs one by one. After all jobs are completed, the onDestroy method is automatically executed without calling the stopSelf () or stopSelf (startId) method. IntentService is not mysterious, but Android encapsulates a common development method to help developers reduce development workload. IntentService is an Assistant class. If Android does not provide this class, we can write a similar one. In addition to IntentService, services are similar to HandlerThread in Handler.
I hope this article will help you understand IntentService.
Related reading:
StartService usage and Service lifecycle in Android
Usage and principles of HandlerThread in Android
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.