IntentService source code detailed

What IntentService can do:
If you have a task, divide it into n subtasks, and need them to complete in order. If you need to put it into a service, then IntentService will make the best choice.

What is IntentService:
IntentService is a Service (looks like nonsense, but when I first saw the name, the first thing I noticed was Intent.), so if you customize an IntentService, you must declare it in AndroidManifest.xml.
From the above "what can be done", we can probably guess what characteristics IntentService should have.
The first thing to be clear is that if you start a Service in an Activity, then the Service is in the main thread. So a worker thread is needed in the IntentService to complete the Intent request. This guess can be confirmed from the definition of IntentService:
IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.

IntentService is used to handle asynchronous requests (sent as Intent) as required. The client sends a request by calling startService(Intent), the service will start as required, and use its own worker thread (different from the UI main thread) to process each Intent (request), and automatically close when all requests are completed.

IntentService source code analysis:
dry goods are coming! The IntentService code includes a worker thread Thread, a worker thread's Looper, and a worker thread's Handler. The worker thread is used for work, the Looper is used to make the thread run, and the Handler is responsible for delivering the work content to the thread. The source code of IntentService concisely and thoroughly reflects this mechanism. Just looking at the mechanics is worth it. The source code is as follows:
Path: alps\frameworks\base\core\java\android\app\IntentService.java
public abstract class IntentService extends Service {  
    private volatile Looper mServiceLooper;  
    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) {
//The custom IntentService subclass mainly implements the function onHandleIntent. Note that after executing this
        //stopSelf, the incoming parameter is startId.  
        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();
//Take a good look at the following code, start a worker thread, get the Looper of the thread, and then use this Looper to initialize the Handler handle
//In this way, you can directly use mHandler.sendMessage to put the task directly on the worker thread.
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");  
    thread.start();  
  
    mServiceLooper = thread.getLooper();  
    mServiceHandler = new ServiceHandler(mServiceLooper);  
}  
  
@Override  
public void onStart(Intent intent, int startId) {
//Get a message from the message queue, generally initialize a message in this way, not in the form of new message()
    //More efficient, more robust code  
    Message msg = mServiceHandler.obtainMessage();  
    msg.arg1 = startId;//  
    msg.obj = intent;//This is the Intent passed in when startService,  
    mServiceHandler.sendMessage(msg);//Pass the message containing the request content Intent to the worker thread  
}  
  
/**
 * 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) {
        //Note that onStart is called, and the value it passed in.  
        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  
    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)}.
     */  
    protected abstract void onHandleIntent(Intent intent);  
}

From thread analysis:
If it is a custom IntentService, you can print Thread.currentThread().getName() in the function to print out the current thread. It will be found that only the execution of onHandleIntent is in another new thread, and the execution of other functions (onCreate/onStart/onStartCommand, etc.) is in the main thread (name of the main thread).

Sample code:
The actual code reference is as follows:
package com.example.fmdemo;  
  
import android.app.IntentService;  
import android.content.Intent;  
import android.os.IBinder;  
import android.util.Log;  
  
public class IntentServiceDemo extends IntentService {  
  
    private static final String TAG = "IntentServiceDemo";  
  
    public IntentServiceDemo() {  
        super("IntentServiceDemo");  
    }  
  
    public IntentServiceDemo(String name) {  
        super(name);  
        // TODO Auto-generated constructor stub  
    }  
  
    @Override  
    protected void onHandleIntent(Intent arg0) {  
        // TODO Auto-generated method stub  
        String action = arg0.getExtras().getString("param");  
        if ("oper1".equals(action)) {  
            Log.i(TAG, "onHandleIntent oper1 threadname = "  
                    + Thread.currentThread().getName());  
        } else if ("oper2".equals(action)) {  
            Log.i(TAG, "onHandleIntent oper2 threadname = "  
                    + Thread.currentThread().getName());  
        }  
  
        try {  
            Thread.sleep(2000);  
        } catch (InterruptedException e) {  
            e.printStackTrace ();  
        }  
    }  
  
    @Override  
    public IBinder onBind(Intent intent) {  
        // TODO Auto-generated method stub  
        Log.i(TAG, "onBind threadname = " + Thread.currentThread().getName());  
        return super.onBind(intent);  
    }  
  
    @Override  
    public void onCreate() {  
        // TODO Auto-generated method stub  
        Log.i(TAG, "onCreate threadname = " + Thread.currentThread().getName());  
        super.onCreate();  
    }  
  
    @Override  
    public void onDestroy() {  
        // TODO Auto-generated method stub  
        Log.i(TAG, "onDestroy threadname = " + Thread.currentThread().getName());  
        super.onDestroy ();  
    }  
  
    @Override  
    public void onStart(Intent intent, int startId) {  
        // TODO Auto-generated method stub  
        Log.i(TAG, "onStart threadname = " + Thread.currentThread().getName());  
        super.onStart(intent, startId);  
    }  
  
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        // TODO Auto-generated method stub  
        Log.i(TAG, "onStartCommand threadname = "  
                + Thread.currentThread().getName());  
        return super.onStartCommand(intent, flags, startId);  
    }  
  
    @Override  
    public void setIntentRedelivery(boolean enabled) {  
        // TODO Auto-generated method stub  
        Log.i(TAG, "setIntentRedelivery threadname = "  
                + Thread.currentThread().getName());  
        super.setIntentRedelivery(enabled);  
    }  
  
}

Add the following code to the onCreate of the custom Activity:
Intent startServiceIntent = new Intent("com.example.fmdemo.intentservice");  
Bundle bundle = new Bundle();  
bundle.putString("param", "oper1");  
startServiceIntent.putExtras(bundle);  
startService(startServiceIntent);  
  
  
Intent startServiceIntent2 = new Intent("com.example.fmdemo.intentservice");  
Bundle bundle2 = new Bundle();  
bundle2.putString("param", "oper2");  
startServiceIntent2.putExtras(bundle2);  
startService(startServiceIntent2);  

The results are as follows:
07-01 06:58:23.557: I/IntentServiceDemo(3732): onCreate threadname = main  
07-01 06:58:23.571: I/IntentServiceDemo(3732): onStartCommand threadname = main  
07-01 06:58:23.571: I/IntentServiceDemo(3732): onStart threadname = main  
07-01 06:58:23.576: I/IntentServiceDemo(3732): onHandleIntent oper1 threadname = IntentService[IntentServiceDemo]  
07-01 06:58:23.577: I/IntentServiceDemo(3732): onStartCommand threadname = main  
07-01 06:58:23.577: I/IntentServiceDemo(3732): onStart threadname = main  
07-01 06:58:25.577: I/IntentServiceDemo(3732): onHandleIntent oper2 threadname = IntentService[IntentServiceDemo]  
07-01 06:58:27.579: I/IntentServiceDemo(3732): onDestroy threadname = main

You can see that onHandleIntent runs in worker threads of different main threads.
IntentService is relatively simple to use, but the implementation mechanism is more interesting. Interested students can type in the code to see it themselves.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327059615&siteId=291194637