Android——Handler原始碼分析

weixin_33978044發表於2017-11-25

從原始碼分析Handler

1、APP的入口 ActivityThread 類的 main()方法,在main方法中呼叫了 Looper.prepareMainLooper();

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

    //Looper的初始化
    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"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    //開始訊息輪循
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

2、Looper.prepareMainLooper()中呼叫了 prepare(false);方法

        public static void prepareMainLooper() {
            prepare(false);
            synchronized (Looper.class) {
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been prepared.");
                }
                sMainLooper = myLooper();
            }
        }

        //quitAllowed 表示是否可以退出此 Looper
        private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }

            //ThreadLocal和 Looper的繫結,即當前執行緒和Looper繫結
            sThreadLocal.set(new Looper(quitAllowed));
        }

3、prepare(false)方法中呼叫 sThreadLocal.set(new Looper(quitAllowed));
完成了 ThreadLocal和 Looper的繫結,即當前執行緒和Looper繫結。

sThreadLocal.set(new Looper(quitAllowed));

//sThreadLocal是Looper的靜態成員變數
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

4、Looper的構造方法中 初始化了 MessageQueue

        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }

5、以上四步完成了 Looper、MessageQueue和ThreadLocal的初始化,

6、在main()方法的最後呼叫了 Looper.loop()方法,這個方法內部是一個死迴圈,這個時候主執行緒的訊息處理機制就執行起來了。

public static void loop() {
    final Looper me = myLooper();
    //...省略
    for (;;) {
        Message msg = queue.next(); // might block可能阻塞,queue.next()取出訊息
        //...省略
        final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        final long end;
        try {
            //在這裡由target(即handler)分發訊息
            msg.target.dispatchMessage(msg);

            end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        //...省略
        msg.recycleUnchecked();
    }
}

7、建立Handler物件,在handler的構造方法中,如果 mLooper 為空,則會丟擲異常。

注意:在子執行緒中建立Handler物件時,要先呼叫 Looper.prepare()方法,完成Looper的初始化,從原始碼中分析,每個執行緒只允許有一個Looper。

public Handler() {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
        }
    }
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = null;
}

8、Handler傳送訊息,最終會呼叫到sendMessageAtTime(Message msg, long uptimeMillis)方法,uptimeMillis引數則表示傳送訊息的時間,它的值等於自系統開機到當前時間的毫秒數再加上延遲時間,SystemClock.uptimeMillis() + delayMillis。如果你呼叫的不是sendMessageDelayed()方法,延遲時間就為0。

public final boolean sendMessageDelayed(Message msg, long delayMillis){
   if (delayMillis < 0) {
       delayMillis = 0;
   }
   return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}


public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
   MessageQueue queue = mQueue;
   if (queue == null) {
       RuntimeException e = new RuntimeException(
               this + " sendMessageAtTime() called with no mQueue");
       Log.w("Looper", e.getMessage(), e);
       return false;
   }
   return enqueueMessage(queue, msg, uptimeMillis);//把訊息加入到訊息佇列(訊息入隊的方法)
}



9、入隊其實就是將所有的訊息按時間來進行排序
//把訊息加入到訊息佇列(訊息入隊的方法)
enqueueMessage(queue, msg, uptimeMillis);

10、訊息出隊方法即 Message msg = queue.next();
// might block可能阻塞,queue.next()取出訊息。

訊息處理即 msg.target.dispatchMessage(msg);
//在這裡由target(即handler)分發訊息。

        public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }

11、一個標準的非同步執行緒 訊息處理寫法:

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

12、另外除了傳送訊息之外,我們還有以下幾種方法可以在子執行緒中進行UI操作:
1. Handler的post()方法
2. View的post()方法(內部實際上也是呼叫的 Handler的post()方法)
3. Activity的runOnUiThread()方法(內部實際上也是呼叫的 Handler的post()方法)

handler.post的原始碼:

public final boolean post(Runnable r)   {
    return  sendMessageDelayed(getPostMessage(r), 0);
}

private final Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;  //直接把傳入的Runnable物件作為callback
    return m;
}

在dispatchMessage()方法中,
if (msg.callback != null) {
    handleCallback(msg);
}

private static void handleCallback(Message message) {
    message.callback.run();//即由Runnable自行處理message
}

Android中為什麼主執行緒不會因為Looper.loop()裡的死迴圈卡死

參考:https://www.zhihu.com/question/34652589

HandlerThread——可迴圈子執行緒

1、HandlerThread繼承自Thread,它的run()中通過Looper.prepare()建立了訊息佇列,並通過Looper.loop()開啟了訊息迴圈。

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

2、使用方法:

    //1、建立HandlerThread
    HandlerThread  handlerThread = new HandlerThread("workHandlerThread");
    handlerThread.start();

    //2、獲取獲取HandlerThread的Looper
    Looper looper = handlerThread.getLooper();

    //3、 建立Handler,通過Looper初始化
    Handler  childHandler = new Handler(looper,mCallback);

    //4、投放非同步耗時任務到HandlerThread中
    // childHandler.sendEmptyMessage(0);

    //4、關閉訊息佇列,釋放執行緒資源
    handlerThread.quit() ;
public class HandlerThreadTestActivity extends BaseActivity {
    private HandlerThread handlerThread;//子執行緒
    private Handler childHandler;//與子執行緒關聯的Handler
  
    private Handler.Callback callback = new Handler.Callback() {
        //子執行緒處理耗時操作的回撥
        @Override
        public boolean handleMessage(Message msg) {
            return false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_thread_test);
        initHandlerThread();
        getData();
    }

    private void initHandlerThread() {
        handlerThread = new HandlerThread("child_thread");  //構造引數為子執行緒的執行緒名
        handlerThread.start();//開啟子執行緒
        childHandler = new Handler(handlerThread.getLooper(),callback);//初始化子執行緒的Handler
    }

    private void getData() {
        //投放非同步耗時任務到HandlerThread中
        childHandler.sendEmptyMessage(0);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //釋放資源
        handlerThread.quit() ;
    }
}

3、使用HandlerThread的好處
3.1、HandlerThread將loop轉到子執行緒中處理,說白了就是將分擔MainLooper的工作量,降低了主執行緒的壓力,使主介面更流暢。
3.2、HandlerThread擁有自己的訊息佇列,它不會干擾或阻塞UI執行緒。
3.3、開啟一個執行緒起到多個執行緒的作用。處理任務是序列執行,按訊息傳送順序進行處理

4、HandlerThread的使用情景

5、Handler 和 Timer

IntentService 內部封裝的就是 HandlerThread

IntentService 是繼承於 Service 並處理非同步請求的一個類,在 IntentService 內有一個工作執行緒來處理耗時操作,啟動 IntentService 的方式和啟動傳統 Service 一樣,同時,當任務執行完後,IntentService 會自動停止,而不需要我們去手動控制。另外,可以啟動 IntentService 多次,而每一個耗時操作會以工作佇列的方式在IntentService 的 onHandleIntent 回撥方法中執行,並且,每次只會執行一個工作執行緒,執行完第一個再執行第二個,以此類推。

所有請求都在一個單執行緒中(HandlerThread),不會阻塞應用程式的主執行緒(UI Thread),同一時間只處理一個請求。

使用IntentService的好處:
1、我們省去了在 Service 中手動開執行緒的麻煩,
2、當操作完成時,我們不用手動停止 Service。

相關文章