經典例子
首先是創建一個 Handler
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
mTextView.setText("更新了UI");
break;
}
}
};
在子線程中更新UI
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000); // 在子線程做一段耗時操作,比如進行網絡請求
mHandler.sendEmptyMessage(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
找到看源碼的切入點
從這個經典的例子中來讀源碼,源碼的切入點就可以從 Handler
的無參構造方法開始看起。
public Handler() {
this(null, false);
}
這個無參構造方法調用了另外一個構造方法 this(null, false);
。去除方法體里面其他的無關代碼,得到關鍵代碼如下
/**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Callback callback, boolean async) {
// ...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
// ...
}
看一下這個兩句話是什么意思
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
看一下 Looper.myLooper()
的實現
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
只是返回一個 Looper
對象而已,也就是獲取了當前線程保存的 Looper
實例,看一下 sThreadLocal
這個變量是什么東西,用 CTRL-F
查找一下代碼,整個 Looper
類中只有這幾個地方有用到 sThreadLocal
變量
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<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);
}
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));
}
主要看 prepare(boolean quitAllowed)
這個方法就可以了。sThreadLocal
是一個 ThreadLocal
對象,可以在一個線程中存儲變量。
1 public static final void prepare() {
2 if (sThreadLocal.get() != null) {
3 throw new RuntimeException("Only one Looper may be created per thread");
4 }
5 sThreadLocal.set(new Looper(true));
6 }
第 5 行新建一個 Looper
對象放入 sThreadLocal
對象。2~4 行判斷 sThreadLocal
中是否已經有 Looper
對象了,如果有就會拋出異常,說明一個線程只能有一個 Looper
對象。
看一下 new Looper(true)
這句話做了什么事情
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
創建了一個消息隊列 MessageQueue
,還有獲取了當前線程的實例。
到這里就不知道要看什么了,那就看一下類的注釋好了,說不定有線索
/**
* Class used to run a message loop for a thread. Threads by default do
* not have a message loop associated with them; to create one, call
* {@link #prepare} in the thread that is to run the loop, and then
* {@link #loop} to have it process messages until the loop is stopped.
*
* <p>Most interaction with a message loop is through the
* {@link Handler} class.
*
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
* 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();
* }
* }</pre>
*/
public final class Looper {
// ...
}
注釋說 Looper
類是用來為一個線程創建一個消息循環用的。線程默認是沒有消息循環的,可以調用 prepare()
創建消息循環,調用 loop()
去處理消息。通常情況下是用 Handler
類和消息循環交互。
這段注釋提到了 prepare()
和 loop()
方法。prepare()
方法剛才已經看過了,那就看一下 loop()
方法做了什么。去掉一些無關的語句,得到
/**
* 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();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// ...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// ...
try {
msg.target.dispatchMessage(msg);
} finally {
// ...
}
// ...
msg.recycleUnchecked();
}
}
這段代碼的大概意思是
無限循環去遍歷消息隊列,取出隊列中的
Message
對象,然后調用msg.target.dispatchMessage(msg);
,然后再把Message
回收了
msg.target.dispatchMessage(msg);
這句話不明白,進入 Message
類看一下是什么東西。
Handler target;
從這里可以知道 Handler
和 Message
有一腿。
再看一下 Handler
類中 dispatchMessage(msg)
方法的實現
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
這里應該就是調用各種回調方法了。從剛才寫的經典例子中,我沒有寫任何的回調方法,因此這個方法體最后就進入了 handleMessage(msg);
方法中。看一下這個方法做了什么
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
這個方法就是經典例子中重寫的 handlerMessage
方法
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
mTextView.setText("更新了UI");
break;
}
}
};
現在梳理一下
- Looper 在
prepare()
方法中創建一個Looper
實例和一個消息隊列 - Looper 在
loop()
方法中不斷地遍歷消息隊列,調用MessageQueue.next()
取出Message
,然后調用和Message
綁定的Handler
的dispatchMessage
方法,去調用各種回調方法
現在幾個疑問
-
Message
是怎么創建的? -
Message
是怎么進入Looper
的消息隊列的? -
Handler
是怎么和Message
綁定在一起的?
Message 是怎么創建的?
在使用 Handler
異步更新 UI 的時候,都會創建 Message
攜帶我們想要傳遞的數據。Message
有幾個屬性可以攜帶數據:
what
、arg1
、arg2
、obj
。用法如下
Message msg = mHandler.obtainMessage();
msg.what = 1;
msg.arg1 = 2;
msg.arg2 = 3;
msg.obj = myObj // myObj 是我們想通過 Message 攜帶的對象
mHandler.sendMessage(msg);
看一下 mHandler.obtainMessage()
做了什么
/**
* Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
* creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
* If you don't want that facility, just call Message.obtain() instead.
*/
public final Message obtainMessage()
{
return Message.obtain(this);
}
又調用了 Message.obtain(this)
,再進入看看
/**
* Same as {@link #obtain()}, but sets the value for the <em>target</em> member on the Message returned.
* @param h Handler to assign to the returned Message object's <em>target</em> member.
* @return A Message object from the global pool.
*/
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
可以看到,為了提高性能,先調用 Message m = obtain();
從消息池中取出一個 Message
,然后再將 Handler
實例賦值給 Message
的 target
屬性,這樣就將 Handler
和 Message
綁定在一起了。
Message是怎么和Handler綁定在一起的?
從上面的
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
我們已經知道了
Message 是怎么進入 Looper 的消息隊列的?
看一下剛才寫的代碼
Message msg = mHandler.obtainMessage();
msg.what = 1;
msg.arg1 = 2;
msg.arg2 = 3;
msg.obj = "想要攜帶的對象";
mHandler.sendMessage(msg);
Message
已經通過 Handler.obtainMessage()
獲取到了,然后就是調用 Handler.sendMessage(Message msg)
發出消息??匆幌?mHandler.sendMessage(msg);
做了什么
/**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
又調用了另外一個方法,再點進去看看
/**
* Enqueue a message into the message queue after all pending messages
* before (current time + delayMillis). You will receive it in
* {@link #handleMessage}, in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
怎么又調用了另外一個方法,再點進去看看
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
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);
}
從這個方法體可以看出,是把剛才我們創建的 Message
加入隊列中去。這里有句話
MessageQueue queue = mQueue;
這個消息隊列是哪里來的?Handler
類中怎么會有消息隊列?用 CTRL-F
查找一下 mQueue =
在哪里出現過
/**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
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();
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;
}
在 Handler
的這個構造方法中找到了 mQueue
被賦值的地方
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
它是通過調用 Looper
的靜態方法 myLooper()
獲取到 Looper
對象,然后再通過 Looper
對象進而獲取到 Looper
的消息隊列的。
知道了 Handler
中的 mQueue
是怎么獲取到的,那就再接著往下看
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);
}
這個方法又調用了 enqueueMessage(queue, msg, uptimeMillis)
,點進去看一下做了什么
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
在這里,這個方法調用了消息隊列 MessageQueue
的 enqueueMessage()
方法把 Message
放進去。
enqueueMessage()
這個方法的方法體代碼太多,我看不懂。不過只需要知道一件事,這個方法的指責是將 Message
放入 MessageQueue
就好了。
梳理Looper、Handler、Message、MessageQueue關系
- Looper 在
prepare()
方法中創建一個Looper
實例和一個消息隊列 - Looper 在
loop()
方法中不斷地遍歷消息隊列,調用MessageQueue.next()
從消息隊列中取出Message
,然后調用和Message
綁定的Handler
的dispatchMessage
方法,去調用各種回調方法 -
Handler
的構造方法會獲得當前線程中的Looper
實例,進而和MessageQueue
關聯在一起 -
Handler
調用sendMessage(Message msg)
,會將msg.target
賦值為自己,然后放入MessageQueue
中 - 我們在構造
Handler
實例的時候,會重寫handleMessage
方法,也就是msg.target.dispatchMessage(msg)
最終調用的方法
Looper.prepare()又是誰來調用的?
從剛才的源碼中,可以知道是通過調用 Looper.prepare()
來創建 Looper
對象。同時,從經典例子中發現,我們沒有去調用 Looper.prepare()
方法。那么 Looper.prepare()
又是誰來調用的?
查了下資料,Android 應用程序的入口是 ActivityThread
的main
函數,那就去看一下 main
函數是怎么實現的,可以看到,在方法體中有一句 Looper.prepareMainLooper();
public final class ActivityThread {
public static void main(String[] args) {
// ...
Looper.prepareMainLooper();
// ...
Looper.loop();
}
}
看一下這個方法的方法體
/**
* 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();
}
}
它調用了 prepare()
創建了 Looper
實例。
以上就是 UI 線程 Looper
創建過程