1. 程式人生 > >Android Handler訊息機制學習

Android Handler訊息機制學習

1.概述

  Handler允許你傳送和處理Message,以及和執行緒相關聯的Runnable物件。每一個Handler例項都與一個執行緒及該執行緒的MessageQueue相關聯。既當你建立一個Handler時,該Handler必須繫結一個執行緒以及該執行緒的訊息佇列,一旦它被建立,它能把messages和runnables傳送到message queue,並在它們從message queue中出來的時候執行它們。

  Handler主要有兩個主要用途:

  • 在未來的某個時間點排程messages和runnables的執行
  • 將要在不同執行緒上執行的操作加入佇列

當你的應用程式被創建出來的時候,主執行緒會專門執行一個message queue來管理最頂級的應用物件(如activities, broadcast receivers,等等)以及它們建立的任何其它視窗。你可以建立你自己的執行緒,通過Handler來與主執行緒建立聯絡

2.原始碼分析

2.1 MessageQueue-訊息佇列

  MessageQueue是一個通過Looper分發它持有的訊息列表的低層級類。Messages沒有直接新增到MessageQueue中,而是通過與Looper相關聯的Handler物件。

  • Message-訊息

該類實現了Parcelable介面,你可以把它看作一個數據類

**
 *
 * Defines a message containing a description and arbitrary data object that can be
 * sent to a {@link Handler}.  This object contains two extra int fields and an
 * extra object field that allow you to not do allocations in many cases.
 * 定義包含描述和任意資料物件的訊息
 * 傳送到Handler。這個物件包含兩個額外的int欄位和一個
 * 額外的物件欄位,允許您在很多情況下不進行分配。
 * <p class="note"
>While the constructor of Message is public, the best way to get * one of these is to call {@link #obtain Message.obtain()} or one of the * {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull * them from a pool of recycled objects.</p> * 注意:不要直接使用New Message()建立Message物件,最好的方式是通過Handler.obtainMessage() * 方法,它會從物件回收池中拉取該訊息物件 */ public final class Message implements Parcelable { /** @hide */ public static final Object sPoolSync = new Object(); /** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. * 從全域性池返回一個新的訊息例項。讓我們在很多情況下避免分配新物件。 */ public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); } ** * Same as {@link #obtain()}, but sets the value for the target member on the Message returned. * 與obtain()相同,但在返回的訊息上設定目標成員的值。 * @return A Message object from the global pool. * 返回來自全域性池的訊息物件 */ public static Message obtain(Handler h) { Message m = obtain(); m.target = h;//接收傳遞過來的Handler return m; } } 複製程式碼

2.2 Looper-訊息輪詢器

  Looper用於為執行緒輪詢messages。執行緒預設是沒有與之相關聯的Lopper,我們必須通過Looper.prepare()方法去建立它。示例:

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();
    }
}
複製程式碼
  • ThreadLocal提供執行緒的區域性變數,通過它訪問執行緒獨立初始化變數的副本。即Looper通過ThreadLocal類來與當前執行緒進行互動
//私用構造方法
//quitAllowed是否允許退出
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);//例項化訊息佇列
    mThread = Thread.currentThread();//獲取當前執行緒
}

/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
* 初始化當前執行緒的Looper
* 在它準備輪詢之前,給你一個時機點去建立一個Handler並引用它
* 呼叫該方法後一定記得Looper.loop()方法,並結束的時候呼叫Looper.quit()方法退出
*/
public static void prepare() {
    prepare(true);
}

// sThreadLocal.get() will return null unless you have called prepare().
//必須先呼叫Looper.prepare()方法,否則返回空
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

private static void prepare(boolean quitAllowed) {
    //每一個執行緒只能有唯一的一個looper
    if (sThreadLocal.get() != null) {//不為空丟擲異常
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));//設定Looper
}

/**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 * 返回與當前執行緒關聯的looper
 */
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 * 在當前執行緒執行訊息隊友
 */
public static void loop() {
    final Looper me = myLooper();//獲取looper
    if (me == null) {//為空則丟擲異常
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;//獲取looper的訊息佇列

    // 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 (;;) {//無限輪詢
        Message msg = queue.next(); // might block
        if (msg == null) { //沒有message則不往下執行
            // No message indicates that the message queue is quitting.
            return;
        }

        ***省略程式碼***
        
        final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
        final long dispatchEnd;
        try {
            msg.target.dispatchMessage(msg);//呼叫Handler的dispatchMessage(msg)方法
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        //回收可能正在使用的訊息。
        //在處理訊息佇列時,MessageQueue和Looper在內部使用。
        msg.recycleUnchecked();
    }
}

//sThreadLocal.get()
public T get() {
    Thread t = Thread.currentThread();//通過Thread的靜態方法獲取當前的執行緒
    //ThreadLocalMap是一個定製的HashMap(),僅適用於維護執行緒區域性值,每一個執行緒都持有一個ThreadLocalMap物件
    ThreadLocalMap map = getMap(t);//傳入當前執行緒獲取當前執行緒的ThreadLocalMap物件
-------------------------------------------------------------------------------—————————————
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
-------------------------------------------------------------------------------—————————————
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}
複製程式碼

2.3 Handler

2.3.1 建立Handler物件

/**
 * Callback interface you can use when instantiating a Handler to avoid
 * having to implement your own subclass of Handler.
 * 如果你不想通過繼承Handler來實現,你必須實現Callback介面
 */
public interface Callback {
    /**
     * @param msg A {@link android.os.Message Message} object
     * @return True if no further handling is desired
     */
    public boolean handleMessage(Message msg);
}
//預設構成器
//如果該Handler所繫結的執行緒沒有looper,它將收不到任何messages,並且會丟擲異常
public Handler() {
    this(null, false);
}
//預設構造器的Callback為空,所以當我們通過new Handler()來建立例項時,
//我們必須重寫Handler的handleMessage(Message msg)方法,即:
companion object {//注意寫成靜態內部類的形式,避免記憶體洩漏
    private class MyHandler :Handler(){
        override fun handleMessage(msg: Message?) {
            super.handleMessage(msg)
        }
    }
}
-------------------------------------------------------------------------------—————————————
//主動實現Callback介面,來建立Handler例項
public Handler(Callback callback) {
    this(callback, false);
}
 companion object {
    private val mHandler1:Handler = Handler(object :Handler.Callback{
        override fun handleMessage(msg: Message?): Boolean {
            return true
        }
    })
    或
    private val mHandler2:Handler = Handler(Handler.Callback {
        true
    })

}
-------------------------------------------------------------------------------—————————————
 /**
 * Use the provided {@link Looper} instead of the default one.
 *
 * @param looper The looper, must not be null.
 * //不使用預設的looper
 */
public Handler(Looper looper) {
    this(looper, null, false);
}
//之前我看到某些前輩是通過下面這種方式來建立Handler例項,通過傳遞主執行緒的looper
//但這是沒必要的,Handler預設就是使用主執行緒的looper(下面會分析)
//並且原始碼註釋也說了,使用你自己的提供的looper而不是預設的
private val mHandler:Handler = object :Handler(Looper.getMainLooper()){
    override fun handleMessage(msg: Message?) {
        super.handleMessage(msg)
    }
}
-------------------------------------------------------------------------------—————————————
//該構造同上,如果你不想重寫handleMessage(msg: Message?)方法,那麼你就重寫Callback介面
public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}
//是否需要非同步處理messages,預設是非同步的
public Handler(boolean async) {
    this(null, async);
}
//自己提供looper,實現Callback介面,決定是否非同步
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

-------------------------------------------------------------------------------—————————————
/*
 * Set this flag to true to detect anonymous, local or member classes
 * that extend this Handler class and that are not static. These kind
 * of classes can potentially create leaks.
 * 將此標誌設定為true以檢測匿名類、本地類或成員類
 * 繼承了Handler不是靜態的,可能存在記憶體洩漏
 */
private static final boolean FIND_POTENTIAL_LEAKS = false;

//通過Handler()、Handler(Callback callback)、Handler(boolean async)
//都會呼叫該構造器
public Handler(Callback callback, boolean async) {
    
    if (FIND_POTENTIAL_LEAKS) {//檢查可能存在的記憶體洩漏,預設是false
        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();//獲取looper
    if (mLooper == null) {//如果為空丟擲異常
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;//獲取Looper中的訊息佇列
    mCallback = callback;
    mAsynchronous = async;
}
private static void handleCallback(Message message) {
    message.callback.run();//執行Message持有的Runnable
}
/**
 * Handle system messages here.
 * 處理系統Messages
 */
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {//如果Message的Runnable不為空
        handleCallback(msg);呼叫Handler的handleMessage(msg)方法處理Message
    } else {
        if (mCallback != null) {//如果Handler的Callback不為空
            if (mCallback.handleMessage(msg)) {//呼叫Callback的handleMessage(msg)方法
                return;
            }
        }
        //否則呼叫Handler的handleMessage(msg)方法
        handleMessage(msg);
    }
}
複製程式碼

2.3.2 建立Message物件

public final Message obtainMessage()
{
    return Message.obtain(this);
}
public final Message obtainMessage(int what)
{
    return Message.obtain(this, what);
}
public final Message obtainMessage(int what, Object obj)
{
    return Message.obtain(this, what, obj);
}
public final Message obtainMessage(int what, int arg1, int arg2)
{
    return Message.obtain(this, what, arg1, arg2);
}
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
    return Message.obtain(this, what, arg1, arg2, obj);
}
複製程式碼

2.3.3 傳送Message

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is 
 * attached. 
 * 將Runnable新增到訊息佇列中。
 * runnable將在此Handler所在的執行緒上執行。
 * 
 * @return Returns true if the Runnable was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 * Runnable成功新增到訊息佇列中返回ture,失敗返回false
 */
public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();建立Message物件
    m.callback = r;把Runnale傳遞給Message
    return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {//延遲時間小於0,則置為0
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//延遲傳送
public final boolean postDelayed(Runnable r, long delayMillis)
{
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}

public final boolean postDelayed(Runnable r, Object token, long delayMillis)
{
    return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}

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

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;//把當前的Handler傳遞給Message的Handler
    if (mAsynchronous) {//是否非同步
        msg.setAsynchronous(true);
    }
    //最終呼叫MessageQueue的enqueueMessage方法
    return queue.enqueueMessage(msg, uptimeMillis);
}
MessageQueue:
boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {//Message的Handler為空,丟擲異常
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {//Message正在使用,丟擲異常
        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();//回收Message
            return false;
        }

        msg.markInUse();設定Message是否正在使用的Flag
        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;
}
複製程式碼

3.總結