1. 程式人生 > >看看Android Handler原始碼

看看Android Handler原始碼

趁著有時間,看看Android原始碼,先來看看Handler,後期的時候在更新吧。都忘記了上次看原始碼是什麼時候了。廢話不哆嗦了,先了解下Handler是幹嘛的,內容簡介啊,原理啊,裡面實現的方法啊,涉及到的設計模式啊,我進來滿足大家,給大家展示,至於寫個什麼樣的demo我還沒想好,不過網上很多了,可以自己去尋找尋找。開始搞起~
加油幹
一.Handler 講什麼的?
每個Handler例項都與一個執行緒和該執行緒的訊息佇列相關聯。當您建立一個新的Handler時,它被繫結到建立它的執行緒/訊息佇列 ——從那開始,它將傳遞訊息傳送該訊息佇列中,並在訊息佇列結束時執行它們。
二.我們主要拿來幹嘛呢?
兩件事兒能幹:
1.排程訊息和程式碼,以便在將來的某個時間執行;
2.對要在不同於您自己的執行緒上執行的操作進行查詢;
三.簡單的畫了一個圖,理解一下Handler+Looper+Message+MessageQueue的工作原理
Handler工作原理簡介

通俗來講:
1.建立一個Handler,然後Handler傳送一個訊息(Message)放在訊息佇列(MessageQueue)中。
2.通過Looper的死迴圈,然後不斷的從訊息佇列中去訊息,然後處理訊息。
3.處理完的訊息,通過Handler的handlerMessage或者是CallBack方法來回調給Handler。
這樣整個過程就完成了。

四. 我們看下Handler中提供的構造方法
1.public Handler()
預設建構函式將此處理程式與當前執行緒的Looper關聯。如果該執行緒沒有迴圈器,則此處理程式將無法接收訊息,因此會引發異常。
2.public Handler(Callback callback)
建構函式將此處理程式與當前執行緒的佇列關聯,並接受一個可在其中處理訊息的回撥介面。
3.public Handler(Looper looper)
使用提供的佇列而不是預設佇列。
4.public Handler(Looper looper, Callback callback)
使用提供的佇列而不是預設佇列,並進行回撥介面,在其中處理訊息。
五.看看裡面我們常用的幾個方法的實現;
1.handler的sendMessage()

    /**
     * Pushes a message onto the end of the message queue after all pending messages
     * before the current time. It will be received in {@link #handleMessage},
     * in the thread attached to this handler.
     *  
     * @return Returns true if the message was successfully placed in to
the * message queue. Returns false on failure, usually because the * looper processing the message queue is exiting. */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }

sendMessage 裡面實現的是一個sendMessageDelayed,那我們繼續看看他的原始碼吧;

/**
     * Enqueue a message into the message queue after all pending messages
     * before (current time + delayMillis). You will receive it in
     * {@link #handleMessage}, in the thread attached to this handler.
     *  
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

其中的2個引數,一個是傳遞的訊息Message、 另外的是我們要執行的延遲時間;按照原始碼中的提示,接著看看下面的sendMessageAtTime方法;

 public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }

啊哈,終於可以看到最終的實現了,簡單的分析一下:
先看看我們建立的MessageQueue中是否有未處理的訊息,之後要看的就是enqueueMessage方法的返回值來判斷是否成功。看看這個方法搞什麼呢?
在MessageQueue中的原始碼看到這個方法如下;

final boolean enqueueMessage(Message msg, long when) {
        if (msg.when != 0) {
            throw new AndroidRuntimeException(msg
                    + " This message is already in use.");
        }
        if (msg.target == null && !mQuitAllowed) {
            throw new RuntimeException("Main thread not allowed to quit");
        }
        synchronized (this) {
            if (mQuiting) {
                RuntimeException e = new RuntimeException(
                    msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            } else if (msg.target == null) {
                mQuiting = true;
            }

            msg.when = when;
            //Log.d("MessageQueue", "Enqueing: " + msg);
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                this.notify();
            } else {
                Message prev = null;
                while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
                }
                msg.next = prev.next;
                prev.next = msg;
                this.notify();
            }
        }
        return true;
    }

1.我們來看下if裡面的條件,如果mMessages物件為空,或者when為0也就是立刻執行,或者新訊息的when時間比mMessages佇列的when時間還要早,符合以上一個條件就把新的msg插到mMessages的前面 並把next指向它,也就是msg會插進上圖中佇列的最前面,等待loop的輪詢。
2.如果上面的條件都不符合就進入else程式碼中,我們可以看到17行是有個for的死迴圈遍歷已有的message物件,其中第20行中有個if語句when < p.when when是新訊息的執行時間,p.when的是佇列中message訊息的執行時間,如果找到比新的message還要晚執行的訊息,就執行 msg.next = p; prev.next = msg; 也就是把插到該訊息的前面,優先執行新的訊息。
其實Handler總結到這裡,我也不知道該說什麼了,簡單的分享一個demo,大家都會的,也讓大家理解一下Handler的應用吧,實現一個倒計時功能;哈哈哈
eg:
在MainActivity中建立一個Handler,然後實現倒計時。程式碼如下:

 private static int TIME = 5;
    private TextView mTime;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    TIME--;
                    mTime.setText(TIME + "s");
                    if (TIME > 0) {
                        Message message = handler.obtainMessage(1);
                        handler.sendMessageDelayed(message, 1000); 
                    } 
            }
            super.handleMessage(msg);
        }
    };

學習的時光總是要花費的,希望大家喜歡我的分享;我的公眾號也可以關注哦。掃碼下面的二維碼即可;
這裡寫圖片描述