Android 之 Handler ,Looper機制詳解

Android 之 Handler ,Looper機制詳解

Handler 在日常開發中異步操作時經常使用到,接下來我們就來分析Handler機制,主要分爲兩大部分:

  • 常見用法
  • 源碼解讀

常見用法

一般我們會在Acticity或者其他地方中new一個Handler ,並重寫handleMessage的方法,在handleMessage中接受傳過來的消息:

    private Handler mHandler = getLocalHandler();
    private final static int FIRST_MESSAGE = 1;
    private final static int SECOND_MESSAGE = 2;

    public Handler getLocalHandler() {
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case FIRST_MESSAGE:
                        //doFirstThing();
                        break;
                    case SECOND_MESSAGE:
                        //doSecondThing();
                        break;
                    default:
                        break;
                }
            }
        };
        return handler;
    }

然後可以在 其他的線程 或者 主線程 發消息給Handler,比如異步網絡加載完數據之後:

    private void sendMessageToFirst() {
        Message msg = new Message();
        msg.obj = null;
        //可用 msg.what 來區別並執行不同的事項
        msg.what = FIRST_MESSAGE;
        mHandler.sendEmptyMessage(FIRST_MESSAGE);
    }

在 異步線程 或 主線程 我們也可以利用Handler來做延時處理操作:

    private void sendMessageDelayed() {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                doSecondThing();
            }
        },2333);
    }

上訴就是我們比較常規的用法。

源碼解讀篇

接下來我們來分析下Handler,Looper機制的java源碼

Handler(初始化):

首先看下new時Handler的構造器,代碼如下:

    public Handler() {
        this(null, false);
    }

    public Handler(Callback callback, boolean async) {
        //...
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException("");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

可以看到,new時初始化 mLooper (Looper) ,mQueue (MessageQueue) ,mCallback (Callback) ,mAsynchronous (Boolean) 這四個對象。
下面我們逐一來分析他們:

Callback :

先說Callback,Callback是Handler類中的接口,其中的handleMessage與我們上述Handler重寫的handleMessage是一樣的方法名:

    public interface Callback {
        public boolean handleMessage(Message msg);
    }

我們直接看他調用的地方,它在dispatchMessage方法中被使用,dispatchMessage(Message msg) 是處理消息的分發的方法,而方法中的 handleMessage(msg) ,它是我們執行 handler中 sendMessage,post(Runnable)等方法的執行語句

    // dispatchMessage方法中被使用,dispatchMessage(Message msg) 
    // 是處理消息的分發的方法

    public void dispatchMessage(Message msg) {
        //..
        // 這個爲callback
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //執行handler中 sendMessage,post等方法的分發執行語句
        handleMessage(msg);
    }

再看下callback調用的地方,可看到當 mCallback != null 且 mCallback.handleMessage(msg) 爲 true 的時候 return 方法不繼續往下走。不然執行handleMessage(msg),這說明我們在 handler 事件執行前多執行一些操作 或者 截斷handler事件的執行,所以可以使用下述的初始化Handler構造器,不過很少使用到這個。

 //Handler.class

 public Handler(Callback callback) {
    this(callback, false);
 }

 Handler handler = new Handler(new Handler.Callback() {
      @Override
      public boolean handleMessage(Message msg) {
           //可以在事件發送前自定義處理
           // doSomeThing();
           return false;
      }
  });

Looper:

接下來我們看下 mLooper 參數,它被賦值了 Looper.myLooper(),我們進Looper進去看,相關代碼貼下去:

    static final ThreadLocal<Looper> sThreadLocal 
         = new ThreadLocal<Looper>();

    public static Looper myLooper() {
        return sThreadLocal.get();
    }

可以看到是從 sThreadLocal 獲取一個Looper,使得且一個線程只有一個Looper,大家可以去網上搜索ThreadLocal的知識理解爲什麼線程只有一個Looper。在 get 之前肯定需初始化,我們找到初始化的地方,代碼如下:

    private static Looper sMainLooper

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

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

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

在代碼中,我們可以看到新建了一個MessageQueue,我們進去看下:

    MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

    void quit(boolean safe) {
        if (!mQuitAllowed) {
                throw new IllegalStateException(
                "Main thread not allowed to quit.");
        }
        // ...
    }

其中quitAllowed代表這個消息隊列是否可以停止,上訴可以看到賦值爲false時,調用quit()方法會報異常, 而mPtr是被底層c++使用,這個我們先不理。此時初始化已經分析完畢。

Handler機制(啓動):

在我們程序啓動時,系統會調用 prepareMainLooper() 方法,並初始化主線程的 Looper ,使主線程有可以使用的 Looper(),其中prepareMainLooper() 中 prepare(false) 會使Looper運行起來且不允許MessageQueue消息隊列中斷,這也可以理解不然在主UI中中斷了可就不好了,代碼如下:

    // ActivityThread.class 主程序的入口

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

在上面可以看到在主程序開始時就就調用了prepareMainLooper()並使Looper loop()了起來,我們看下loop()方法,代碼如下 :

 public static void loop() {
        final Looper me = myLooper();
        // ...
        final MessageQueue queue = me.mQueue;
        // ...
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) { 
                return;
            }
            // ...
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                // ...
            }
            // ...
            msg.recycleUnchecked();
        }
    }

可以看到方法中,獲取當前MessageQueue對象,並開啓了死循環,當queue.next()消息隊列沒有消息就return繼續等待,有消息的話就往下執行 msg.target.dispatchMessage(msg) 語句。我們去先下queue.next()中的內容,代碼如下:

    // MessageQueue.class

    Message next() {
        // 當loop被停止或者棄用 ptr 爲0
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }
        //...

        // 下一次消息觸發時間
        int nextPollTimeoutMillis = 0;

        for (;;) { 
            //...
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                // 如果同步時執行 且 msg.target == null執行
                if (msg != null && msg.target == null) {
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (
                    msg != null && !msg.isAsynchronous());
                }

                if (msg != null) {
                    if (now < msg.when) {
                        nextPollTimeoutMillis 
                        = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    nextPollTimeoutMillis = -1;
                }
                if (mQuitting) {
                    dispose();
                    return null;
                }
            }
            //...
        }
    }

我們可以看到通過next()方法,我們可以獲取消息繼而執行,接着target是什麼,代碼如下:

    // Message.class

    Handler target;

可以看到 target 是個Handler對象,之前有稍微講下Handler的dispatchMessage()方法,讓我們再看一遍詳細代碼:

    // Handler.class

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

    public void handleMessage(Message msg) {
    }

可以看到當傳下來的消息msg中的callback不爲空的時候,直接執行run()方法,不然就判斷mCallback 是否爲空且mCallback.handleMessage(msg)是否爲true,不然就執行我們重寫的handleMessage()方法。
那麼target又是哪裏賦值的呢,我們先看Message的構造器,代碼如下:

    // Message.class
    public Message() {
    }

發現並沒有賦值target的值,我們回想一般在新建Message消息後我們會發送出來,我們去那個方法看下:

    // Handler.class
    public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 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) {
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    private boolean enqueueMessage(MessageQueue queue, 
                        Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

到最後我們可以發現target = this爲我們當前的Handler,最後我們看下enqueueMessage方法,代碼如下:

    // MessageQueue.class
    boolean enqueueMessage(Message msg, long when) {
        //...
        synchronized (this) {
            if (mQuitting) {
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;

            // mMessages可以理解爲上一次Message
            // 當mMessages不爲空,或者啓動時間爲0的,或者啓動時間小於mMessages的啓動時間
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                // 循環將消息插入隊列之中
                for (; ; ) {
                    prev = p;
                    p = p.next;

                    // 當下個無消息的時候
                    // 或者當前消息啓動時間小於下個的啓動時間,跳出循環
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p;
                prev.next = msg;
            }

            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

上述代碼就是Message插入隊列的代碼。

總結:

Handler機制其實在Android機制中算比較好理解的,我們可以看到主要涉及的類有Handler,Looper,MessageQueue和Message。
在主線程中,
Handler:負責對外,比如消息的添加,移除等功能,
Looper:個人理解作爲一個載體,承載着消息隊列的啓動,獲取及銷燬消息,使Handler不必對MessageQueue進行管理,專注處理對外事件的處理
MessageQueue:對消息的循環移除,及對C++代碼的通信。其中涉及到部分的jni代碼本篇暫時還沒解析,有興趣的同學可以自行了解或谷歌。
這也是本人的第一篇博客,如果有什麼寫的錯誤或者不足的,請大家留言幫忙糾錯!0-0

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