1. 程式人生 > >Android IntentService原始碼理解 及 HandlerThread構建訊息迴圈機制分析

Android IntentService原始碼理解 及 HandlerThread構建訊息迴圈機制分析

  前言:前面寫了Handler的原始碼理解,關於Handler在我們Android開發中是到處能見到的非同步通訊方式。那麼,在Android原生裡,有那些也有到了Handler機制的呢?有很多,比如我們今天所要理解分析的IntentService就使用到了Handler。接下來,我們來深入瞭解一下。

  HandlerThread:

  IntentService使用到了Handler+HandlerThread構建的帶有訊息迴圈的非同步任務處理機制,我們先簡單看一下HandlerThread是如何工作的吧。

  HandlerThread的使用步驟:

        // 建立HandlerThread例項
HandlerThread handlerThread = new HandlerThread("handlerThread"); // 啟動HandlerThread執行緒 handlerThread.start(); // 構建訊息迴圈處理機制 Handler handler = new Handler(handlerThread.getLooper(), new Handler.Callback() { @Override public boolean
handleMessage(Message msg) { return false; } });

  以上三步的順序不能亂,必須嚴格按照步驟來。第三步是將HandlerThread物件中的looper物件作為Handler第一個引數,我們由前面的Handler解析可知道,我們指定了Looper物件,那我們的handler的執行緒looper物件就不用新建,而是使用當前傳入的執行緒的looper物件。

  第一步,建立HandlerThread物件,HandlerThread我們能看到,它繼承自Thread,它有兩個建構函式

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

  兩個構造方法的都需要傳一個任意字串引數,引數的主要作用就是指定該執行緒的名稱;第二個構造方法多傳一個優先順序引數,不傳則預設第一個構造方法中的Process.THREAD_PRIORITY_DEFAULT,根據需求自行決定即可;

  第二步,啟動HandlerThread執行緒,為什麼我們必須要先啟動HandlerThread,我們來看看run()就明白了

    @Override
    public void run() {
     // 獲得當前執行緒的id mTid
= Process.myTid();
     // 準備迴圈條件 Looper.prepare();
     // 持有鎖機制來獲得當前執行緒的Looper物件
synchronized (this) { mLooper = Looper.myLooper();
       // 發出通知,當前執行緒已經建立mLooper物件成功,這裡主要是通知getLooper方法中的wait notifyAll(); }
     // 設定當前執行緒的優先順序 Process.setThreadPriority(mPriority);
     // 該方法實現體是空的,子類可以實現該方法,作用就是線上程迴圈之前做一些準備工作,當然子類也可以不實現。   onLooperPrepared();
     // 啟動loop Looper.loop(); mTid
= -1; }

  程式碼註釋寫的非常清楚了,在run()方法中主要是呼叫了Looper.prepare()和Loop.loop()構建了一個迴圈執行緒;我們可以注意一下的是,在loop()循前呼叫了onLooperPreapared()方法,這個方法可自行實現,做一些執行緒迴圈之前的準備工作,這就有了很好的拓展性了;notifyAll()主要是通知getLooper()中的wait,我們看一下getLooper()方法;

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        // 如果執行緒已啟動,looper物件為空,則繼續等待,前面的喚醒就可以喚醒當前的等待
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

  第三步,構建訊息迴圈機制,該步驟這裡就不詳細說了,前面《Android非同步訊息處理機制掌握,從原始碼瞭解常使用的Handler》看過後就能理解了。

  OK,我們講了這麼多HandlerThread的分析理解,那麼IntentService的理解就比較容易了,我們現在來看看IntentService吧;

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

  IntentService是繼承自Service的,是啟動一個服務進行非同步任務處理的,該服務會在執行完任務後自行終止;IntentService的建構函式很簡單,傳入一個字串引數,指定執行緒名稱;

  我們都知道Service服務生命週期是從onCreate方法開始的,首先來看看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);
    }

  很開心,我們剛剛分析的HandlerThread在這裡出現了。onCreate方法建立了一個迴圈的工作執行緒HandlerThread,然後將HandlerThread當前執行緒的looper物件傳給Handler作為引數建立一個訊息執行者,通過Handler+HandlerThread構建了一個帶有訊息迴圈機制的非同步任務處理機制;ServiveHandler是IntentService的一個內部類,繼承Handler;

  Service服務第二步生命週期執行onStartCommand方法;

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

  我們看到該方法僅僅呼叫了onStart方法,在IntentService的子類中無需重寫該方法,系統會在IntentService接受一個請求開始呼叫該方法;

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

  該方法就是通過ServiceHandler獲取一個Message物件,將非同步訊息請求的intent封裝進Message中,併發送給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);
        }
    }

  實現很簡單,繼承Handler,在重寫訊息處理方法中呼叫IntentService的onHandleIntent方法,onHandleIntent方法也是我們使用IntentService需要重寫的方法,在這個我們進行我們的非同步任務操作。為什麼可以在這裡進行非同步任務操作,當非同步任務結束後,呼叫stopSelf方法自動結束該IntentService服務。前面HandlerThread理解後我們可以知道這裡的handleMessage是在工作執行緒中執行的;那這樣我們就達到了非同步任務處理的目的了。

  

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

  onHandleIntent方法是我們使用IntentService的時候在子類需要重寫的方法。通過註釋我們可以知道,每一次只能處理一個intent意圖請求,當有多個請求時(客戶端多次呼叫startCommand方法),其他intent暫時會被阻塞掛起,直到前面的intent請求處理完成才會繼續處理下一個intent請求。處理完成請求後,呼叫stopSelf方法停止當前服務,然後會繼而呼叫Service的onDestroy生命週期方法,從而達到處理完成任務後,服務銷燬;

    public final void stopSelf(int startId) {
        if (mActivityManager == null) {
            return;
        }
        try {
            mActivityManager.stopServiceToken(
                    new ComponentName(this, mClassName), mToken, startId);
        } catch (RemoteException ex) {
        }
    }
    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

  總結:IntentService是一種非同步任務處理的方式,繼承自Service,使用IntentService需在子類重寫onHandleIntent方法,進行非同步任務。只要當前服務沒有銷燬,客戶端可以發起多個Intent請求,looper會迴圈獲取請求,一個接一個地進行處理。