Android Handler消息機制原碼解讀

android的消息機制包括:handler(處理者)、looper(循環)、messageQueue(消息隊列)、message消息。

這裏先理解一個消息隊列這個概念,handler的消息隊列是先進先出的鏈表結構,下面是模擬消息隊列寫的一些方法。

消息類的寫法

public class MessageData {
    //傳遞的數據類型,以作判斷
    public int status;
    //你需要處理的數據
    public Object data;
    //用於連接消息的類
    public MessageData message;
    //最多連接數,這裏沒做處理
    public int linkedSize = 0;

}

消息隊列的寫法

public class MessageQueueData {
    private MessageData messageData;

   //入隊:將消息存入消息隊列中
    public void enqueueMessage(MessageData messageData) {
        Log.e("MessageQueueData", "enqueueMessage:" + messageData.status);
        //判斷消息隊列是否爲空,如果爲空,就講鏈條的第一個消息置位假如的消息
        if (this.messageData == null) {
            this.messageData = messageData;
            this.messageData.message = null;
        } else {
            //如果不爲空,進行鏈條循環,
            //將鏈條的第一數據賦值
            MessageData tempMy = this.messageData;
            MessageData tempInner;
            for (; ; ) {
                //取出該數據中用於連接的數據
                tempInner = tempMy.message;
                //如果該數據不爲空,將該數據置爲鏈條的類
                if (tempInner != null) {
                    tempMy = tempInner;
                } else {
                    //如果該數據爲空,將該數據假如鏈條,結束循環
                    tempMy.message = messageData;
                    break;
                }

            }

        }

    }
    //出隊,將消息從消息隊列中取出
    public void next() {
        if (this.messageData != null) {
            Log.e("MessageQueueData", "next:" + this.messageData.status);
            //取出消息,將內部連接到該類中
            this.messageData = this.messageData.message;
        }
    }

}

執行過後的數據爲

這裏就體現出了先進先出的邏輯,好了,下面自定義一個looper循環的定時器

 private class HandlerThread extends Thread {

        private Handler mHandler;
        private TimmerRunnable mTimmerRunnable;
        private int time = 0;

        public HandlerThread() {
            mTimmerRunnable = new TimmerRunnable();
        }

        @Override
        public void run() {
            super.run();
            //創建該線程的looper,一個線程只能創建一個looper
            Looper.prepare();
            //創建該線程的handler
            mHandler = new Handler();
            //發送消息,及消息入隊
            mHandler.post(mTimmerRunnable);
            //開始循環,進入循環獲取消息
            Looper.loop();
        }

        public void stopThread() {
            //退出循環,結束線程
            mHandler.getLooper().quit();
        }

        private class TimmerRunnable implements Runnable {

            @Override
            public void run() {
                //消息會送,在這裏處理你的消息,這樣就實現了一個消息循環了,完成定時器
                time++;
                tv_time.post(new Runnable() {
                    @Override
                    public void run() {
                        tv_time.setText("時間:" + time);
                    }
                });
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mHandler.post(mTimmerRunnable);
            }
        }

    }

先從創建開始,這裏調用looper的prepare()

//先調用的這個方法
 public static void prepare() {
        prepare(true);
    }

//做空判斷,如果該線程已近存在looper了就會拋出異常,所以一個線程只能有一個looper
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中
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

Handler的創建

//沒有傳入參數的構造方法
 public Handler() {
        this(null, false);
    }
//調用的是該構造函數
 public Handler(Callback callback, boolean async) {
        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());
            }
        }
        //獲取該線程的looper,如果該線程的looper不存在,就會拋出異常
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        //將looper創建的MessageQueue賦值到handler中
        mQueue = mLooper.mQueue;
        //消息處理接口,用於從消息隊列出去後發送回主界面,以便於實現你的代碼
        mCallback = callback;
        mAsynchronous = async;
    }

接下來進入Looper的循環機制

//進入循環
public static void loop() {
        //獲取該線程的looper,如果爲空則拋出異常
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //獲取looper中創建的消息隊列
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;
        //進入死循環,循環讀取消息隊列中的消息
        for (;;) {
            //獲取消息隊列的消息,如果消息隊列返還爲空,則跳出循環結束該方法
            //消息隊列中,當隊列中的消息問空的時候會進入死循環,這裏會進入阻塞狀態
            //只用手動調用queue.quit()方法纔會返回空,然後結束該方法,結束線程
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                //經過一些列的數據處理,當到達這裏的時候,將Message小心中的handler取出來
                //然後調用handler的dispatchMessage方法,將消息進行分發
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           …………
            //釋放Message,將Message數據重置,然後開始下一次消息的讀取
            msg.recycleUnchecked();
        }
    }

消息隊列的數據讀取,出隊,MessageQueue.next方法

Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                //賦值消息隊列首部的消息
                Message msg = mMessages;
                //判斷該消息和該消息保存的handler是
                //如果該消息不爲空,但是該消息的handler爲空,進入
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        //賦值,將該消息賦值給prevMsg,同時取出該消息內部存儲的消息,
                        //賦值到msg中
                        prevMsg = msg;
                        msg = msg.next;
                        //滿足條件,則繼讀取下一個鏈條的數據
                    } while (msg != null && !msg.isAsynchronous());
                }
                //如果不爲空
                if (msg != null) {
                    if (now < msg.when) {
                        //下一條消息還沒有準備好。設置一個超時,當它準備好時喚醒。
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            //將該鏈條的首位置於讀取後鏈條的下一個數據
                            mMessages = msg.next;
                        }
                        //將出隊的消息的鏈條剪短,將下一個數據置空
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        //改變消息隊列該鏈條的狀態
                        msg.markInUse();
                        //返還該鏈條的數據
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                 //手動調用quit方法,結束該方法,返還空,到looper.loop層,然後結束該線程
                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }
……………………
        }
    }

接下來是消息分發了,handler.dispatchMessage方法

/**
     * Handle system messages here.
     */
//這裏是判斷調用的是handler的post方法還是sendMessage方法
    public void dispatchMessage(Message msg) {
        //取出保存在message的handler的callback方法,如果該保存了該方法,就調用回調的
        //post方法中的
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
        //如果調用的是sendMessage方法,就會調用handleMessage,需要在創建Handler中重新改方法
        //收取數據
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

這樣就完成了出隊的所有流程了。

接下來是入隊,入隊分爲handler.post和handler.sendMessage兩種方法入隊

先討論handler.post方法

  public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
//創建Message
private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }
//進入到這個方法中
  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);
    }
//在這個方法中開始進入MessageQueue的入隊方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

下面是MessageQueue中的enqueueMessage方法

boolean enqueueMessage(Message msg, long when) {
        //當message中沒有保存handler的時候拋出異常
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            //當鏈表中第一個位置的數據不存在的時候,將保持的數據加入到鏈條首位
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                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; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        //加入成功
        return true;
    }

至此,hander的入隊出隊就完成了

 

 

 

 

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