本系列筆記是我閱讀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造成異常