Handler源碼學習(一)流程

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

1.創建handler — 默認構造方法會獲取當前線程的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) {
        //警告潛在內存泄漏風險
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
          //如果是匿名類,內部類等等并且不是static 有內存泄露風險
            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
        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 如果當前線程已經有一個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();
        }
    }
//構造方法,創建了一個消息隊列
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設置成當前的這個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,這里是個無限循環
msg.target.dispatchMessage(msg);

5.dispatchMessage() — 分發消息

//三種情況,
//第一種Message對象的callback不為空(runnable),交給callback處理,第一種大多是使用post方法傳入runnable對象時會調用
//第二種是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可以在構造方法中傳入
//Message的callback可以在obtain方法中作為參數傳入,注意,一個消息被使用完畢后會被recycle,callback也會被移除,所以只能使用一次

6.post — 各種post方法

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

//不被推薦使用的方法,很容易導致消息隊列清空,排序問題,以及其它副作用
//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()
//如果當前線程是ui線程就直接調用run方法,如果不是當前線程則通過handler發送消息
public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}
  • view.post()
//首先會判斷這個view是否已經attach上了window,如果是的話會使用handler來發送消息
//否則會加入到消息隊列中,等到attach了才會一次取出執行
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只被創建一次,且跟當前線程綁定,一個looper。

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

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

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

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

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

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容