Android HandlerThread源碼分析

HandlerThread繼承自Thread,該類實現了一個帶有Looper的線程,ThreadHandler中的Looper可以被用於創建一個Handler,這樣可以通過在線程中處理handler中的消息隊列;
當然,HandlerThread的實例必須調用start()方法纔可以讓處理Handler發送的消息,也就是說HandlerThread必須是運行狀態的。

源碼分析

在HandlerThread類中,核心代碼就是在run()方法中創建一個Looper對象。這樣就可以通過handler在子線程中處理消息。

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

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

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

    /**
     * 在looper啓動之前,可用於初始化一些設置
     */
    protected void onLooperPrepared() {
    }

    /**
     * 在線程中創建Looper
     */
    @Override
    public void run() {
        mTid = Process.myTid();
        // 1、創建Looper,該looper對象實際被存儲在ThreadLocal對象中
        Looper.prepare();
        synchronized (this) {
            // 2、獲取Looper對象,通過ThreadLocal.get()獲取Looper對象
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        // 3、啓動looper消息循環,在消息隊列中獲取消息,該方法是一個阻塞的方法
        Looper.loop();
        mTid = -1;
    }

    /**
     * 獲取該線程中的Looper對象
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // 當looper被創建後該方法才返回looper對象
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    /**
     * 該方法可以返回一個帶有該Looper的Handler的對象,但是該方法被隱藏
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

    /**
     * 退出handlerThread的looper循環
     *
     * 通過該方法退出looper循環,將會移除消息隊列中的所有未處理消息
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }


    /**
     * 退出handlerThread的looper循環
     *
     * 通過該方法退出looper循環,將會清楚所有pending的消息,但是對於已經存在於消息隊列中的消息,handler將會繼續處理完成後纔會退出循環。
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    /**
     * 返回線程id
     */
    public int getThreadId() {
        return mTid;
    }
}

通過上面的代碼我們可以知道,一旦HandlerThread調用start()方法啓動後,Looper對象會一直阻塞等待處理消息隊列中的消息,直到你線程調用quit()或quitSafely()方法,looper循環器纔會停止運行,整個線程纔會停止。

HandlerThread使用場景

通常情況下,都是通過HandlerThread在子線程中執行耗時的操作。同時,因爲在HandlerThread中是通過Looper維護的消息隊列,所以線程在處理任務時時同步的,所以就不需要考慮併發的問題。

代碼示例:

HandlerThread handlerThread = new HandlerThread("WorkThread");
handlerThread.start();

Handler handler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // 這裏可以執行耗時操作,因爲在子線程中

    }
};

IntentService

在android源碼中,有一個IntentService的服務類,該類繼承自Service,主要功能就是讓Service在子線程中處理任務,在該類中就是通過HandlerThread實現的。

關於IntentService的介紹,請看 Android IntentService源碼分析

Handler、Thread和HandlerTrhead的關係

一句簡單的話總結這三者的關係就是:
HandlerThread就是一個在Thread中實現handler的機制的一個具體實現。

在這裏明確一個概念,如果想在子線程中創建Handler,那麼必須在handler初始化前爲該線程創建一個Looper對象,否則會拋出一個運行時異常:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
                                                       at android.os.Handler.<init>(Handler.java:200)
                                                       at android.os.Handler.<init>(Handler.java:114)
                                                       at com.zhangke.componentdemo.MainActivity$1.run(MainActivity.java:30)

通常情況下,我們通過下面的代碼爲線程創建Looper:

  class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {

          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }

關於HandlerThread的介紹就到這裏了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章