Copyright notice: This article is the blogger’s original article, welcome to reprint!
Reprint please indicate the source: blog.csdn.net/guiying712/… This article is from: [Zhang Huayang’s blog]
In this article, I will introduce IntentService in Android. While analyzing the principle of IntentService, I will also analyze HandlerThread used in IntentService.
IntentService
IntentService inherits Service from Android’s four main components. The difference between IntentService and Service is that it can handle asynchronous requests. As we all know, the code in Service runs on the main thread by default. ANR problems can easily occur if time-consuming tasks are handled directly in a Service, whereas IntentService works directly in child threads. In addition, when we start IntentService with the startService(Intent) method, IntentService will process each Intent in the worker thread and stop itself after completing the task.
Before analyzing the source code, let’s look at how to use IntentService:
public class MyIntentService extends IntentService { public MyIntentService() { super("MyIntentService"); Override protected void onHandleIntent(Intent Intent) {// Print the name of the current thread, Log.d("MyIntentService", "Thread id is "+ thread.currentThread ().getName()); } @Override public void onDestroy() { super.onDestroy(); Log.d("MyIntentService", "onDestroy"); }}Copy the code
IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService In the onHandleIntent method, you can handle some specific business logic without worrying about ANR because the method is already running in a child thread.
IntentService IntentService
public class IntentService extends Service { private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler; private String mName; 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); } } @WorkerThread protected abstract void onHandleIntent(@Nullable Intent intent); /** * 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; } @Override public void onCreate() { 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); } @Override public void onDestroy() { mServiceLooper.quit(); }}Copy the code
The reason why the constructor of MyIntentService must call the parent’s argument constructor is because IntentService needs to give its worker thread a name that can be used to distinguish between them when we debug. We can verify this with this code in the onCreate() method:
HandlerThread thread = new HandlerThread(” IntentService[” + mName + “] “); // mName is the argument we passed in the constructor
IntentService (Context, Intent) : IntentService (Context, Intent) : IntentService (Context, Intent) : IntentService (Context, Intent) : IntentService (Context, Intent) : IntentService (Context, Intent) : IntentService (Context, Intent) : IntentService (Context, Intent)
1. First create a HandlerThread in the onCreate() callback and start the thread. Then get the Looper created in the HandlerThread and use the Looper to create a ServiceHandler.
OnStart (@nullable Intent Intent Intent, int startId); Make the Message carry our request parameters, and then send the Message out via ServiceHandler. If you don’t understand how Handler works, check out this article: Android Handler source code parsing.
The Message sent by ServiceHandler is eventually distributed to the handleMessage(Message MSG) method of ServiceHandler, an inner class of IntentService. IntentService’s abstract method onHandleIntent(@nullable Intent Intent) is called and annotated with @workerthread, indicating that the method was called in the WorkerThread. The stopSelf method of the Service is then called to stop the Service, so you don’t need to call the stopSelf method.
Once IntentService calls stopSelf, onDestroy() is called back, and the Looper we created in HandlerThread exits the loop.
Note the following when using IntentService:
OnHandleIntent (IntentService) : IntentService (IntentService) : IntentService (IntentService) : IntentService (IntentService) : IntentService (IntentService) : IntentService (IntentService) : IntentService (IntentService) : IntentService (IntentService) : IntentService (IntentService) : IntentService (IntentService)
2. Do not provide Service onBind in your IntentService. You do not need to implement this method because IntentService implements it by default and returns null.
HandlerThread
IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService: IntentService The Looper created in this new thread can be used to create Handler classes, so handlerThreads are often used with handlers, which is why the class name is HandlerThread.
Note: The start() method of the Thread class still needs to be called.
We have already seen how HandlerThread is used in IntentService, so we will directly look at the source code of HandlerThread:
public class HandlerThread extends Thread { Looper mLooper; private @Nullable Handler mHandler; protected void onLooperPrepared() { } @Override public void run() { ... Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); }... onLooperPrepared(); Looper.loop(); . } public Looper getLooper() { if (! isAlive()) { return null; } // If the thread has been started, wait until the looper has been created. synchronized (this) { while (isAlive() && mLooper == null) { try { wait(); } catch (InterruptedException e) { } } } return mLooper; } public boolean quit() { Looper looper = getLooper(); if (looper ! = null) { looper.quit(); return true; } return false; }}Copy the code
Before looking at the source code for HandlerThread, let’s review Java threads.
In Java, each Thread completes its operations through a method run() corresponding to a particular Thread object. The method run() is called the Thread body, which contains the contents of the Thread to be executed. We can start a Thread by calling the start() method of the Thread class. Once start() is called, the Thread is placed in a waiting queue for CPU scheduling, but execution does not have to start immediately, just put the Thread into an active line state.
In Java, threads typically have five states: created, ready, running, blocked, and dead:
The first is to create state. The thread object is created without calling its start method. The second is readiness. When the start method of a thread object is called, the thread is ready, but the thread scheduler has not set the thread to the current thread. The thread is also in the ready state after it runs, after it comes back from waiting or sleeping. The third is the running state. The thread scheduler sets the thread in the ready state to the current thread, at which point the thread enters the run state and starts running the code in the run function. The fourth is blocking. A thread is paused while it is running, usually to wait for an event to occur (such as a resource being ready) before continuing. Methods like sleep, suspend, and wait can all cause threads to block. The fifth is death. If a thread’s run method finishes or stops, the thread dies. For dead threads, you can no longer use the start method to get them ready.
In the run() method of HandlerThread, looper.prepare () is called to create a Looper in the current thread, and looper.mylooper () is used to retrieve the Looper. Next we execute the onLooperPrepared() method, which we can override if we need to do something before Looper goes into an infinite loop. Looper. Loop () is then called to start Looper.
Next we look at the getLooper() method of HandlerThread, which returns the Looper associated with the current thread (the Looper created in run()), GetLooper () will return null if the Thread is not started (which is why the start() method is called after the HandlerThread is created) or if isAlive() returns false for some reason. If the thread is already started, getLooper() blocks until Looper initialization is complete.
Notice that the quit() method is also provided for exiting the HandlerThread’s Looper, Since IntentService actively calls looper.quit() to exit looper during destruction, you should also actively call quit() after using HandlerThread.