HandlerThread和IntentService的使用詳解

在Android開發(fā)中,我們知道可以在主線程中直接使用Handler,這是因為在APP的入口,系統(tǒng)就已經(jīng)調(diào)用Looper.prepareMainLooper(),和Looper.loop(),但是如果我們想在子線程使用handler,也很簡單,只要先使用Looper.prepare();然后調(diào)用Looper.loop()后,就可使用handler了,但是可能有些小伙伴覺得也麻煩,是不是應該有一種對這種進行封裝的框架呢?沒錯,系統(tǒng)里有個HandlerThread就是干這件事的。

我們來看看HandlerThread的使用:

        HandlerThread thread = new HandlerThread("MyHandlerThread");
        thread.start();

        Looper looper = thread.getLooper();
        MyHandler myHandler = new MyHandler(this,looper);

首先,創(chuàng)建一個HandlerThread對象,然后必須先調(diào)用start()方法,因為HandlerThread是繼承Thread的,調(diào)用start()開啟線程的執(zhí)行,可以看一下其run()方法的源碼:

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

可以看到,run方法里面做了對Looper的初始化操作,初始化完成后回調(diào)了onLooperPrepared()方法,當我們需要做一些在Looper初始化完成并在開啟輪詢之前的操作的時候,我們就可以繼承該類然后復寫自己的onLooperPrepared方法做我們需要的工作,這樣設計增加了其擴展性。

下面我們回到主線程的使用當中,接著調(diào)用thread.getLooper(),看一下該方法源碼:

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

首先,判斷Looper的線程是否存活的,然后進入同步代碼塊中,此代碼塊是個while循環(huán),如果線程是存活的并且mLoope這時還沒有被初始化好,這時該線程(主線程)就會等待,等到mLoope初始化好之后,子線程會調(diào)用notifyAll()來喚醒,然后返回mLooper。

接下來我們就可以使用返回的Looper創(chuàng)建Handler了:
MyHandler myHandler = new MyHandler(this,looper);
這樣通過此handler發(fā)送的消息都會被創(chuàng)建此Looper的子線程拿去處理了。

我們再來看一下HandlerThread的一個典型的應用:系統(tǒng)為我們提供的IntentService ,先貼出其源碼:


package android.app;

import android.annotation.WorkerThread;
import android.annotation.Nullable;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;


/**
 * IntentService is a base class for {@link Service}s that handle asynchronous
 * requests (expressed as {@link Intent}s) on demand.  Clients send requests
 * through {@link android.content.Context#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.
 */
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) {
            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.
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

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

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

    @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
    @Nullable
    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)}.
     *               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);


}

先介紹一下IntentService,這是一個Service的子類,專門用來在子線程處理異步任務的,處理完成之后會自動的結(jié)束服務。
我們可以看到,在onCreate()方法中使用了HandlerThread,和我們之前那段代碼幾乎差不多,在onStart方法中通過Handler將intent信息發(fā)送到消息隊列中,然后在子線程中調(diào)用handleMessage方法去處理 ,這里可以看到handleMessage方法中,先調(diào)用了onHandleIntent((Intent)msg.obj),這是個抽象方法,需要我們自己去實現(xiàn),我們可以在其中做一些耗時的任務,任務完成之后會自動調(diào)用stopSelf(msg.arg1)結(jié)束服務。在onDestroy中調(diào)用mServiceLooper.quit()結(jié)束消息隊列,防止此Service出現(xiàn)內(nèi)存泄漏。當我們多次調(diào)用startService開啟服務時,會走onStartCommand方法,從源碼中看到,它也會調(diào)用onStart(intent, startId)方法,然后將intent信息發(fā)送過去,由此,我們能得出,當有多個任務時,這些任務都被依次的存入子線程的消息隊列中,待子線程一個一個取出去處理,如果前面的任務耗時,則會阻塞后面的任務。
這里有一點需要了解一下,前面講了在任務處理完成之后會調(diào)用stopSelf(msg.arg1)結(jié)束服務,那么你也許會問:如果消息隊列中有多個任務,既然第一個任務完成之后就把服務給結(jié)束了,那之后的任務怎么辦?
這里我們就需要來看看stopSelf(msg.arg1)的源碼了:

/**
     * Old version of {@link #stopSelfResult} that doesn't return a result.
     *  
     * @see #stopSelfResult
     */
    public final void stopSelf(int startId) {
        if (mActivityManager == null) {
            return;
        }
        try {
            mActivityManager.stopServiceToken(
                    new ComponentName(this, mClassName), mToken, startId);
        } catch (RemoteException ex) {
        }
    }

可以看到是通過AIDL調(diào)用ActivityManagerService來停止服務的,關于怎么關閉的,這里就不介紹了,有興趣的可以去看看源碼,這里我們看其官方注釋,提示此方法是stopSelfResult的老版本,我們來看看stopSelfResult的源碼:

/**
     * Stop the service if the most recent time it was started was 
     * <var>startId</var>.  This is the same as calling {@link 
     * android.content.Context#stopService} for this particular service but allows you to 
     * safely avoid stopping if there is a start request from a client that you 
     * haven't yet seen in {@link #onStart}. 
     * 
     * <p><em>Be careful about ordering of your calls to this function.</em>.
     * If you call this function with the most-recently received ID before
     * you have called it for previously received IDs, the service will be
     * immediately stopped anyway.  If you may end up processing IDs out
     * of order (such as by dispatching them on separate threads), then you
     * are responsible for stopping them in the same order you received them.</p>
     * 
     * @param startId The most recent start identifier received in {@link 
     *                #onStart}.
     * @return Returns true if the startId matches the last start request
     * and the service will be stopped, else false.
     *  
     * @see #stopSelf()
     */
    public final boolean stopSelfResult(int startId) {
        if (mActivityManager == null) {
            return false;
        }
        try {
            return mActivityManager.stopServiceToken(
                    new ComponentName(this, mClassName), mToken, startId);
        } catch (RemoteException ex) {
        }
        return false;
    }

代碼和stopSelf幾乎差不多,就是返回值從void改變?yōu)閎oolean,意味著這個并方法不一定能真正的停掉服務,我們再來看看方法參數(shù)和返回值的注釋:

@param startId The most recent start identifier received in {@link #onStart}.
@return Returns true if the startId matches the last start request and the service will be stopped, else false.

startId是通過onStart方法接收的ID。
如果需要關閉的startId和最后一次請求服務的時候的startId相匹配,就停止服務,如果不匹配,則不停止。什么意思?就是說如果你多次調(diào)用startService啟動了服務,此時最后“最后一次請求服務的時候的startId”就是你最后請求的那個startID,也就是說只有最后的那個startID才能停止掉服務,之前的都不行,明白了吧。其實,這才符合實際,如果你的Service要同時處理多個請求,你就不能在當前一個請求處理完成之后立刻停止Service,因為很可能現(xiàn)在你已經(jīng)收到了一個新的啟動Service請求(如果立刻停止,那么新來的請求就會跟著終止)。為了避免這種情況發(fā)生,你可以用stopSelf(int)來保證你當前停止Service的請求是基于上一個請求的。也就是說,當你調(diào)用stopSelf(int),你把startID傳給了對應的要停止的Service,這個startID是上一個請求的StartID!!如果沒有第二個請求來,那么這個Service就會死掉,但是如果這個Service已經(jīng)又接受到一個新的啟動請求之后,你才調(diào)用stopSelf(int),那么你傳遞給stopSelf()的ID是上一個請求的ID,而當前Service的startID已經(jīng)更新為新的請求的ID,造成兩個ID不對應,stopSelf()失效,那么Service就不會停止。這樣就避免了將后面的請求終止。

最后總結(jié)一下:

  1. 對于HandlerThread的使用,要先調(diào)用其start方法做Looper的初始化操作,然后調(diào)用HandlerThread的getLooper方法來獲取looper,此方法是個阻塞的方法,直到Looper初始化完成才能被喚醒,最后將looper傳入Handle中使用。
  2. IntentService是系統(tǒng)為我們封裝的一個Service,其原理是通過HandlerThread來實現(xiàn)的,我們在使用時只需基礎IntentService并實現(xiàn)onHandleIntent方法,在方法中具體處理我們的耗時任務,如果有多個任務,則這些任務會在子線程的消息隊列中排隊等待被處理,并且處理完最后一個任務時,才會停止掉該服務。
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容