Handler源碼學(xué)習(xí)(一)流程

本系列筆記是我閱讀Handler及相關(guān)類的源碼時所記錄的一些之前所不知道的知識點,該系列分為三部分,整體流程,Message對象回收原理,MessageQueue管理隊列
Handler源碼學(xué)習(xí)(一)流程
Handler源碼學(xué)習(xí)(二)Message對象池
Handler源碼學(xué)習(xí)(三)MessageQueue入隊插隊

1.創(chuàng)建handler — 默認構(gòu)造方法會獲取當(dāng)前線程的looper,也可以傳入指定的looper

/**
 * Default constructor associates this handler with the {@link Looper} for the
 * current thread.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 */
public Handler() {
    this(null, false);
}
public Handler(Callback callback, boolean async) {
        //警告潛在內(nèi)存泄漏風(fēng)險
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
          //如果是匿名類,內(nèi)部類等等并且不是static 有內(nèi)存泄露風(fēng)險
            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());
            }
        }
        //創(chuàng)建looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

2.Looper

/** 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()}.
  */
public static void prepare() {
    prepare(true);
}
//用ThreadLocal來存放looper 如果當(dāng)前線程已經(jīng)有一個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));
}

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

//主線程的looper
/**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
//構(gòu)造方法,創(chuàng)建了一個消息隊列
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

3.sendMessage

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);
}
//handler中將message添加到消息隊列
//將這個message的target設(shè)置成當(dāng)前的這個handler
 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

4.loop() — 取出消息

//target是handler,這里是個無限循環(huán)
msg.target.dispatchMessage(msg);

5.dispatchMessage() — 分發(fā)消息

//三種情況,
//第一種Message對象的callback不為空(runnable),交給callback處理,第一種大多是使用post方法傳入runnable對象時會調(diào)用
//第二種是handler的callback不為空,交給callback處理,callback
//前兩種都沒有的情況下交給handleMessag去處理
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 interface Callback {
        public boolean handleMessage(Message msg);
    }
//Handler的callback可以在構(gòu)造方法中傳入
//Message的callback可以在obtain方法中作為參數(shù)傳入,注意,一個消息被使用完畢后會被recycle,callback也會被移除,所以只能使用一次

6.post — 各種post方法

//注意傳入的runnable的run方法會在handler所綁定的looper所在線程中執(zhí)行,最終還是sendMessageDelayed()
public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

//不被推薦使用的方法,很容易導(dǎo)致消息隊列清空,排序問題,以及其它副作用
//Posts a message to an object that implements Runnable.
//Causes the Runnable r to executed on the next iteration through the
//message queue.
//This method is only for use in very special circumstances -- it
//can easily starve the message queue, cause ordering problems, or have
//other unexpected side-effects.</b>
public final boolean sendMessageAtFrontOfQueue(Message msg) {
        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, 0);
    }

8.擴展

  • runOnUiThread()
//如果當(dāng)前線程是ui線程就直接調(diào)用run方法,如果不是當(dāng)前線程則通過handler發(fā)送消息
public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}
  • view.post()
//首先會判斷這個view是否已經(jīng)attach上了window,如果是的話會使用handler來發(fā)送消息
//否則會加入到消息隊列中,等到attach了才會一次取出執(zhí)行
public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().post(action);
    return true;
}

7.收獲

1.looper是通過 ThreadLoacal來保存 ,保證looper只被創(chuàng)建一次,且跟當(dāng)前線程綁定,一個looper。

2.handler有多個構(gòu)造方法,并不是必須要重寫handleMessage方法,可以通過傳入callback對象來處理消息,同時也可以給handler指定looper,因此handler可以給其它線程的looper發(fā)送消息。

3.MessageQueue不由handler創(chuàng)建,而是從looper中獲取,一個looper對應(yīng)有一個MessageQueue,因此一個looper必然可以對應(yīng)多個handler,它們都是往這同一個消息隊列中發(fā)送消息而已

4.Android中的主線程會調(diào)用Looper.prepareMainLooper() 方法來創(chuàng)建一個looper,因此不需要我們手動創(chuàng)建looper

5.handler發(fā)送延遲消息時,是通過但前時間+delayed時間,在某個時間去發(fā)送,因此如果在插入message時的時間是0,會容易導(dǎo)致排序問題

6.每一個Activity在創(chuàng)建的時候其實就已經(jīng)創(chuàng)建了一個handler,runOnUiThread方法中使用的就是這個handler

7.view.post除了異步更新ui外還有一個作用,可以判斷當(dāng)前view是否已經(jīng)attach window,在這個runnable任務(wù)被執(zhí)行時,可以拿到尺寸等等,避免因為disattach造成異常

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容