Handler學習

剛開始學習Android的時候,知道異步線程沒法更新UI,因而找了個能把更新的動做拋給UI線程的東西,這個東西就是Handler。併發

一開始就只會在主線程也就是UI線程new一個Handler,以後在各個子線程裏面使用,並沒想過一些原理的東西,其實須要學習的知識還有不少。異步

1、線程之間的同步ide

A. 子線程向主線程發送消息,咱們一開始學習的都是這種比較簡單方式。oop

    一、主線程中new Handler,並實現handleMessage方法post

    二、子線程中得到主線程Handler的實例學習

    三、子線程向主線程發消息sendMessageui

B. 主線程向子線程發送消息:this

#點擊按鈕向mThread線程發送消息    
mStartBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ...... mHandler.sendMessage(......); } }); mThread.start(); ...... Thread mThread = new Thread(new Runnable() { @Override public void run() { Looper.prepare(); #實例化Handler,實現handleMessage mHandler = new Handler(){ @Override public void handleMessage(Message msg) { ...... } }; Looper.loop(); } });

經過這個咱們比較直觀的看見相同和不一樣的地方:spa

    相同的地方:A線程向B線程發送消息,A須要拿到B實例化的Handler對象線程

   不一樣的地方:子線程多了下面兩個東西:

Looper.prepare();
.......
Looper.loop();

其實說不一樣的地方,其實只是咱們實現的時候不須要寫Looper,可是主線程同樣須要有Looper,那麼很容易想到,Android已經給咱們寫好了,後面有具體講。

2、Looper,Handler,Message

Looper:

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }

Looper在建立的時候會初始化一個MessageQueue,這個是用來存儲Message的管道

    public static void loop() {
        final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; ...... for (;;) { Message msg = queue.next(); // might block ...... final long end; try { msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } ...... } }

在loop的時候會循環的從MessageQueue取Message,而後分發Message。msg.target其實就是Handler,因而Handler就能夠得到數據並進行處理。

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

上面的仍是比較有意思的,這裏簡單總結下:

  1. msg.callback不爲空,執行msg.callback.run
  2. mCallback不爲null,執行mCallback.handleMessage(msg),可能會執行第3中狀況
  3. 最後可能會執行Handler自己的handleMessage(msg)方法。

通常的是3這種狀況,1發生在使用Handler在異步線程中直接更新UI的狀況。

    Thread mThread = new Thread(new Runnable() {
        @Override
        public void run() { mHandler.post(new Runnable() { @Override public void run() { textView.setText("xxxx"); } }); } });

其實mHandler.post也是發送了一個消息,而後把Runnable傳給Message並處理。

總結下:

Looper其實就是建立一個循環獲取消息併發送Handler的類。

Message其實就是一個數據存儲的類,用於傳輸數據。

Handler就是進行發送和介紹處理的類。

這三個配合起來一塊兒用,才能構建了handler線程之間傳遞數據的機制。

 

問題一:上面所說的須要Looper,Handler,Message配合使用才能完成這個工做,那麼我寫子線程向主線程時怎麼沒看到主線程的Looper呢?

這個咱們能夠去看下Activity的源碼,其實在ActivityThread裏面已經寫好了這個東西,全部咱們不須要寫了。

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

        Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); ...... Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }

注意:寫在Looper.loop();後面的代碼是沒法執行。

相關文章
相關標籤/搜索