Handler的一點理論分析

小編發表於2018-12-23

ThreadLocal

ThreadLocal是一個執行緒內部的資料儲存類。它可以為各執行緒儲存資料,同時只能由當前執行緒獲取到儲存的資料,對於其他執行緒來說則獲取不到。它可以在不同執行緒中維護一套資料的副本,並且彼此互不干擾。

一言不合上程式碼:

private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
public static void main(String[] args) {
    threadLocal.set(1);
    System.out.println(Thread.currentThread().getName() + "--value:"
            + threadLocal.get());

    new Thread("Thread#1") {
        public void run() {
            threadLocal.set(2);
            System.out.println(Thread.currentThread().getName() + "--value:"
                    + threadLocal.get());
        };
    }.start();

    new Thread("Thread#2") {
        public void run() {
            System.out.println(Thread.currentThread().getName() + "--value:"
                    + threadLocal.get());
        };
    }.start();
}複製程式碼

輸出結果為:

main--value:1
Thread#1--value:2
Thread#2--value:null複製程式碼

ThreadLocal內部為當前執行緒維護了一個ThreadLocalMap。key是ThreadLocal物件,value則是需要設定的值,儲存在Entry中。

注意

Handler建立時,會獲取到訊息佇列和當前執行緒的Looper物件來構建訊息迴圈系統,那麼如何獲取到當前執行緒的Looper呢?就是用到ThreadLocal,它儲存了Looper物件。保證了不同執行緒間提供對應的Looper物件。

因此保證了一個執行緒只有一個Looper物件

注意:執行緒是預設沒有Looper的,如果需要使用Handler,就必須為執行緒建立Looper。

只所以可以在Activity中直接例項化Handler,是因為ActivityThread作為程式的入口,已經例項化好了Looper物件。

public final class ActivityThread {
    // 省略...

    public static void main(String[] args) {
        // 省略...
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
}複製程式碼

因此如果需要在子執行緒中使用Handler,則必須先例項化Looper。

   new Thread("Thread#1"){
       @Override
       public void run() {
           Looper.prepare();
           Handler handler = new Handler();
           handler.sendEmptyMessage(0);
           Looper.loop();
       }
   }.start();複製程式碼

相關文章