本系列筆記是我閱讀Handler及相關(guān)類的源碼時(shí)所記錄的一些之前所不知道的知識點(diǎn),該系列分為三部分艺蝴,整體流程凸椿,Message對象回收原理肠槽,MessageQueue管理隊(duì)列
Handler源碼學(xué)習(xí)(一)流程
Handler源碼學(xué)習(xí)(二)Message對象池
Handler源碼學(xué)習(xí)(三)MessageQueue入隊(duì)插隊(duì)
1.創(chuàng)建handler — 默認(rèn)構(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)險(xiǎn)
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
//如果是匿名類阔加,內(nèi)部類等等并且不是static 有內(nèi)存泄露風(fēng)險(xiǎn)
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)建了一個消息隊(duì)列
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添加到消息隊(duì)列
//將這個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對象時(shí)會調(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)致消息隊(duì)列清空戴卜,排序問題,以及其它副作用
//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.擴(kuò)展
- 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ā)送消息
//否則會加入到消息隊(duì)列中师脂,等到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對象來處理消息拌消,同時(shí)也可以給handler指定looper,因此handler可以給其它線程的looper發(fā)送消息安券。
3.MessageQueue不由handler創(chuàng)建墩崩,而是從looper中獲取,一個looper對應(yīng)有一個MessageQueue侯勉,因此一個looper必然可以對應(yīng)多個handler鹦筹,它們都是往這同一個消息隊(duì)列中發(fā)送消息而已
4.Android中的主線程會調(diào)用Looper.prepareMainLooper() 方法來創(chuàng)建一個looper,因此不需要我們手動創(chuàng)建looper
5.handler發(fā)送延遲消息時(shí)址貌,是通過但前時(shí)間+delayed時(shí)間铐拐,在某個時(shí)間去發(fā)送,因此如果在插入message時(shí)的時(shí)間是0练对,會容易導(dǎo)致排序問題
6.每一個Activity在創(chuàng)建的時(shí)候其實(shí)就已經(jīng)創(chuàng)建了一個handler遍蟋,runOnUiThread方法中使用的就是這個handler
7.view.post除了異步更新ui外還有一個作用,可以判斷當(dāng)前view是否已經(jīng)attach window螟凭,在這個runnable任務(wù)被執(zhí)行時(shí)虚青,可以拿到尺寸等等,避免因?yàn)閐isattach造成異常