HanderThread源碼分析

前言

在讀這篇文章之前最好先讀一下我之前寫的關於Handler原理的文章:Android Handler消息源碼分析,這樣會比較容易理解handlerThread的原理。

內容

HandlerThread相信很多人都已經用過,還不瞭解或者沒有用過的同學請自行搜索。

先貼一下sample code

   HandlerThread handlerThread = new HandlerThread("sample");
   handlerThread.start();
   Handler handler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
       @Override
       public boolean handleMessage(Message msg) {
           Log.v("test","handleMessage");
           return false;
       }
   });
   for(int i=0;i<10;i++){
       try {
           Thread.sleep(1000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       handler.sendMessage(Message.obtain());
   }

廢話不多講,直接看HandlerThread的構造方法

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

因爲HandlerThread類是繼承自Thread類,所以先調用父類的方法,將Thread Name賦值,接着設置線程優先級。
接着在sample code中會調用start()方法,我們知道這個會讓線程開始運行,並調用run()方法,所以我們直接看run()方法。

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

主要工作內容就是調用Looper.prepare(),初始化Looper對象,並給mLooper賦值。我們知道Looper.prepare()方法在哪個線程調用,這個Looper就屬於哪個線程,所以在這裏這個Looper就屬於HandlerThread這個子線程。接着加一個鎖,給mLooper賦值,然後通知等待線程。這段代碼是對應於後面的另一個getLooper()方法,然後調用onLooperPrepared(),這個是空方法,子類在繼承HandlerThread的時候可以重寫這個方法,這樣可以在消息循環真正跑起來之前做一些準備工作,然後再調用Looper.loop(),讓消息循環真正跑起來。

我們繼續看sample code,

  Handler handler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
      @Override
      public boolean handleMessage(Message msg) {
          Log.v("test","handleMessage");
          return false;
      }
  });

就是初始化一個Handler對象,將handlerThread的Looper作爲參數專遞給handler,這樣做的作用是handler之後發送的消息就會送到這個handlerThread的子線程,而不是我們通常在使用的MainThread即UI線程。我們這裏重點看一下handlerThread.getLooper()方法。

    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason isAlive() returns false, this method will return null. If this thread
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    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;
    }

從方法註釋我們知道,只有當線程是live狀態的時候纔可以返回值,否則就返回null,這裏面也有一個鎖,大致邏輯就是如果發現mLooper是null則等待,直到被喚醒,那誰會喚醒它呢?從前面的分析知道,這個mLooper是在run方法裏被賦值,也是在run方法裏被賦值後喚醒getLooper方法中的鎖,這個就實現了只要調用getLooper方法,就可以獲得子線程looper的目的。

接下來就是用handler調用SendMessage給handlerThread發送消息了,這個中間的原理在之前的:Android Handler消息源碼分析已經講過,這裏不再重複。最後調用handlerThread.quitSafely()方法退出HandlerThread的消息循環

    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

邏輯就是安全的退出消息循環,然後從run()方法返回,線程結束。handler還有另外一個退出方法就是quit(),這兩個方法的區別是,quitSafely()在退出線程之前會分發完消息隊列中剩下的message,但有個例外,就是通過postDelay方法發送的延遲消息也不會被分發,,而quit是直接退出,不管消息隊列中還有沒有消息,至於選擇哪個方法,就看具體使用場景了。好了,就講到這裏,是不是很簡單。

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