IntentService for Android multithreading

Keywords: Android Design Pattern Multithreading

####What is IntentService?

IntentService inherits from Service, so IntentService is also one of the four major components. IntentService encapsulates the HandlerThread thread thread (only one thread) to process asynchronous tasks in sequence. Start IntentService through startService(Intent) and transmit asynchronous tasks through Intent. When the task ends, IntentService passes * stopSelf(int startId) To stop the Service yourself. IntentService is an abstract class. If you want to use IntentService, first create a class to inherit IntentService, and then override onHandleIntent(Intent) * to process the tasks passed by Intent in the child thread.

IntentService features:

  • onHandleIntent(Intent) occurs in the child thread. You cannot directly update the UI. You need to send the result to the Activity first
  • The submitted tasks are executed in sequence. If A task A is executing in IntentService and another asynchronous task B is sent to IntentService, Task B will not start executing until task A is executed
  • Tasks already executed in IntentService will not be interrupted

####IntentService usage example

Effect drawing first:

We can see that we started the first task first. When the first task has not been completed, we started the second task. The second task will not be executed immediately, but will not start the second download task until the first task is downloaded to 100%. This verifies that IntentService will execute asynchronous tasks in sequence. See the specific implementation, First inherit an IntentService and override onHandleIntent():

public class MyIntentService extends IntentService {
    public static final String ACTION_ONE = "action_one";
    public static final String ACTION_TWO = "action_two";
    private int progressOne, progressTwo;

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (intent == null) return;
        String action = intent.getAction();
        switch (action) {
            case ACTION_ONE:
                while (progressOne < 100) {
                    progressOne++;
                    sendBroadcast(getUpdateIntent(0, progressOne));
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case ACTION_TWO:
                while (progressTwo < 100) {
                    progressTwo++;
                    sendBroadcast(getUpdateIntent(1, progressTwo));
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                break;
        }
    }
 }

onHandleIntent() is executed in the child thread. It receives tasks through Intent and then executes the tasks, and continuously sends the operation results to the Activity through BroadCastReceiver to update the UI. When all tasks are completed, IntentService will close automatically. We see that tasks are processed in IntentService, so where are the tasks transmitted here? Look at the following code:

 Intent intent = new Intent(IntentServiceActivity.this, MyIntentService.class);
 intent.setAction(MyIntentService.ACTION_ONE);
 startService(intent);

We see that we can directly start and transfer tasks to IntentService through startService(Intent). Finally, don't forget to define IntentService in AndroidManifest.xml:

 <service
     android:name=".multiThread.intentService.MyIntentService"
     android:screenOrientation="portrait" />

Full source address: IntentService for Android multithreading

####IntentService source code analysis

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    public IntentService(String name) {
        super();
        mName = name;
    }

First, define the variable and pass in the name of the worker thread in the constructor.

    @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 int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

The execution sequence of the above three methods in IntentService: oncreate > onstartcommand > OnStart:

1. Initialize a HandlerThread thread and start it in onCreate(), then initialize a ServiceHandler and pass the Looper in the HandlerThread as a parameter to ServiceHandler, so that messages can be sent to the HandlerThread subprocess through ServiceHandler in the main thread for processing; 2. onStart() is called again in onStartCommand() and returns start according to mRedelivery_ REDELIVER_ Intent or START_NOT_STICKY, what's the difference between the two? Let's review the return value in onStartCommand():

  • START_STICKY: if the service process is kill ed, keep the service status as the start status, but do not keep the delivered intent object. Then the system will try to re create the service. Since the service state is in the start state, the onStartCommand(Intent,int,int) method will be called after the service is created. If no start command is passed to the service during this period, the parameter intent will be null.

  • START_NOT_STICKY: "non viscous". When using this return value, if the service is abnormally kill ed after onStartCommand is executed, the system will not automatically restart the service

  • START_STICKY_COMPATIBILITY: START_STICKY is a compatible version, but there is no guarantee that the service will restart after being kill ed.

  • START_FLAG_REDELIVERY: if you implement onStartCommand() to schedule asynchronous work or work in another thread, you may need to use START_FLAG_REDELIVERY to make the system resend an Intent. In this way, if your service is killed while processing it, Intent will not be lost

So when you return to start_ FLAG_ During redelivery, if the Service is abnormally killed, the Intent will be sent again after the Service is restarted; If you return to START_NOT_STICKY: when the Service is killed by an exception, it will not be restarted.

3. In onStart(), the Intent is encapsulated in the Message and sent to the HandlerThread through ServiceHandler. The Message is retrieved through loop. Loop() in HandlerThread, and finally the ServiceHandler processes the Message. So let's look at ServiceHandler:

   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);

In handleMessage(), we found that the onHandleIntent() method was callback. This method is an abstract method, and we must implement it in the subclass, so we need to deal with the final message carefully. Note that this callback method is implemented in Zi Xiancheng. After executing onHandleIntent(), we call stopSelf to close ourselves. IntentService callback onDestroy() when closing:

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

We see that mserviceloop. Quit() is called at the end of IntentService to stop the loop in HandlerThread, that is, the HandlerThread will not block but exit when there is no task.

Posted by dotti on Fri, 15 Oct 2021 12:45:38 -0700