天天看點

IntentService全面分析講解

一、簡介

我們在《HandlerThread全面分析講解》中全面分析了HandlerThread的原理和應用,而IntentService中核心元素就是HandlerThread,也可以說是HandlerThread的另一種使用場景。

本質:IntentService的本質是Service服務。前面我們在《關于Service服務常用的知識》中也講到了,Service服務運作在主線程,如果有耗時操作的話,需要在服務中建立子線程,而HandlerThread本質又是線程,是以IntentService算是Thread和Service的結合使用場景。IntentService本身是抽象類,是以算是在普通Service的基礎上加了一個就有消息機制的子線程并對相關功能進行了封裝。

特質:當所有任務完成後,IntentService會自動停止。

擁有較高的優先級,不易被系統殺死,是以比較适合執行一些高優先級的異步任務。

使用方式簡單,建立IntentService子類,實作onHandlerIntent方法和構造方法,onHandlerIntent為異步方法,可以執行耗時操作。

二、跟蹤源碼,分析IntentService的工作原理

1、建立子類時,要重寫的方法
public class CustomIntentService extends IntentService {
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public CustomIntentService(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // 處理耗時操作
    }
}
           
2、IntentService的本質是普通Service,是以和Service服務的特質是一樣的,跟蹤onCreate()方法
@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();
    // 關鍵一
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
   thread.start();

   // 關鍵二
   mServiceLooper = thread.getLooper();
   // 關鍵三
   mServiceHandler = new ServiceHandler(mServiceLooper);
}
           
  • onCreate()方法是服務第一次被建立的時候調用
  • 關鍵一:建立一個HanlerThread,我們知道HandlerThread本質是Thread,是一個擁有Looper的Thread,是一個擁有消息機制必備元素的子線程。
  • 關鍵二:擷取擁有Looper元素的線程的Looper對象。
  • 關鍵三:外部建立Handler元素,與HandlerThread的Looper對象進行綁定,組成一個完整的消息機制。
3、Handler處理消息
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);
    }
}
           
  • 關鍵一:Handler綁定的是子線程的Looper,是以Handler的dispatchMessage()方法會在子線程中調用,是以handleMessage()方法中的工作都是在子線程中完成的。
  • 關鍵二:最終使用者隻需實作onHandlerIntent()方法即可。
  • 關鍵三:onHandleIntent中的工作完後,會自動關閉服務。

4、啟動服務

@Override
public void onStart(@Nullable Intent intent, int startId) {
    // 關鍵一
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}

/**
 * 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(@Nullable Intent intent, int flags, int startId) {
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
           
  • 通過與線程綁定的Handler将Message發送到子線程的隊列中。

    從子線程的隊列中取出消息最後處理消息,就回到了上一步的handleMessage方法中。

5、整個消息機制了解起來還是很抽象的,有一個很關鍵的點一定要了解記住,那就是Looper.java檔案中的loop()方法
/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    
    final MessageQueue queue = me.mQueue;
    for (;;) {
        // MessageQueue類的讀取方法
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        try {
            // 取出資料後,交由發送者(Handler)處理消息
            msg.target.dispatchMessage(msg);
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        
        msg.recycleUnchecked();
    }
}
           
  • 整個精簡後的代碼邏輯就是擷取到目前線程持有的Looper對象,擷取到Looper對象所持有的消息隊列MessageQueue,然後從消息隊列中一個一個的取出消息(調用next()方法),從取出的消息中擷取儲存的Handler對象(即這條Message的發送者),調用Handler的dispatchMessage()方法,将消息交由Handler去處理。 msg.target.dispatchMessage(msg);這句話可是在工作線程中調用的,是以Handler的handleMessage()方法中的代碼運作在工作線程。

6、最後看看使用者需調用的方法

/**
 * 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)}.
 *               This may be null if the service is being restarted after
 *               its process has gone away; see
 *               {@link android.app.Service#onStartCommand}
 *               for details.
 */
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
           
  • 關鍵一:This method is invoked on the worker thread with a request to process. 正如我們上面所講,該方法在工作線程上調用。
  • 關鍵二:每次隻能處理一個Intent,是以使用IntentService處理異步任務隻能是串聯執行無法并聯執行。
  • 關鍵三:因為是串聯執行,所有如果有一個Intent耗時比較久,會影響後面的Intent的執行時間。
  • 關鍵四:所有Intent執行完畢之後會自動執行stopSelf()方法,無需手動調用。

三、總結

關于IntentService的原理和簡單的使用都講完了。其實無論是HandlerThread還是IntentService都是官方幫我們封裝的工具類,因為一些功能我們經常會用到,是以才有了這些官方工具類,省去了我們自己手動封裝。正因為我們會遇到跨線程進行通信,工作線程有時候需要持有Looper建立自己的消息機制,是以有了HandlerThread。正因為Service服務運作在主線程,無法運作耗時任務,需在服務中建立子線程,是以利用HandlerThread的特性封裝出了IntentService。但是這些工具類都有自己的特性,在使用前一定要分析好自己的需求特性是否和這些工具類特性相比對。比如,IntentService隻能是串聯執行,如果想在服務中同時運作多個工作線程,那還是需要在服務中手動建立線程池,開啟多個工作線程,同時并行多個任務。

繼續閱讀