介紹
本文是自己看Handler源碼的一個流程,主要對主線進行了追蹤查看。
如有寫的不正確或者分析不正確的,麻煩大佬指出。跪謝啦!
Handler機制涉及主要相關類
- Handler
發消息、處理消息
- Looper
輪詢消息隊列,一個線程只有一個Looper
- Message
消息的存儲對像
- MessageQueue
消息列表(消息不會直接添加到MessageQueue中,
而是通過與Looper關聯的{@link Handler}對象)
先拋出幾個問題:
- Looper什麼時候創建的?
- MessageQueue什麼時候創建的?
- Looper和當前線程是什麼時候綁定的?
- Message和Handler什麼時候綁定的?
- Message什麼時候放入MessageQueue?
源碼追蹤
new Handler();
先從new 一個Handler看起:
點進去,看到Handler構造方法裏調用了
mLooper = Looper.myLooper();
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();// 這裏獲取一個Looper
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;
}
關鍵方法: Looper.myLooper()
myLooper();點進去發現是sThreadLocal.get()直接獲取的。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
而sThreadLocal是一個用來存儲Looper的本地變量
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
我們再去查看sThreadLocal 哪裏調用了。
發現只有三個地方調用了,有一個調用的方法是直接設置Looper的:
sThreadLocal.set(new Looper(quitAllowed)); 發現這裏直接是new Looper。
關鍵方法:sThreadLocal.set(new Looper(quitAllowed));
繼續追蹤,發現sThreadLocal.set(new Looper(quitAllowed)); 是在prepare方法裏調用的。
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));
}
到這裏我們發現了這是Looper的創建時間!
好奇寶寶肯定點擊進去看下的:new Looper();我們點擊看下
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
// 是不是發現了什麼,MessageQueue在Looper的構造方法裏創建的,同時Looper和線程也綁定了
總結: Looper的創建時間,也是MessageQueue創建的時間,同時 也是Looper和線程綁定的時間。
關鍵方法:prepare
繼續追蹤,誰又調用了prepare呢
prepare();
public static void prepare() { // 消息隊列可以quit
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));
}
繼續追蹤,發現 Looper.class 的107行調用的prepare(false);
public static void prepareMainLooper() {
prepare(false); // 這裏調用的prepare。//消息隊列不可以quit
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
再繼續追蹤prepareMainLooper ,我們會追蹤到ActivityThread這個類裏面。
prepareMainLooper()
主線程就是UI線程,Activity由ActivityThread啓動,會調用ActivityThread的main函數:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// 省略N行代碼................
Looper.prepareMainLooper(); // 看到這裏我們就明白了,
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 省略N行代碼................
Looper.loop();// 開始輪詢
throw new RuntimeException("Main thread loop unexpectedly exited");
}
我們從使用Handler處追蹤,到這裏我們是往上層追蹤到ActivityThread的**main(String[]args)**方法裏。
這就證明了Looper的創建時間,Activity啓動時就會爲ui線程創建一個Looper。Looper構造方法裏進行MessageQueue的創建、Looper和線程的綁定。**
關鍵方法流程:
new Handler() ---->
Looper.myLooper() ---->
sThreadLocal.set(new Looper(quitAllowed)) ---->
prepare(boolean quitAllowed) ---->
prepareMainLooper()---->
ActivityThread的main(String[] args)
附上流程圖:
Message的創建、以及與Handler的綁定
消息創建
Message obtain = Message.obtain();也可以直接new Message ();使用obtain很更好點,看下方源碼上的註釋:
//obtain 源碼中有很多這個方法,這裏只拷貝出這兩個
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
* 從全局池返回一個新的消息實例。讓我們
*在很多情況下避免分配新對象
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
//這裏也可以直接綁定Handler,即使不綁定Handler中enqueueMessage也會去綁定的
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
Message與Handler的綁定、Message放入MessageQueue
handler發送消息的幾個方法:
- sendEmptyMessage()
- sendEmptyMessageAtTime()
- sendEmptyMessageDelayed()
- sendMessageAtFrontOfQueue();
- sendMessage()
- sendMessageAtTime()
- sendMessageDelayed
我們換個方向從這裏作爲入口去追蹤 Message與Handler的綁定:
點擊去一直往下追蹤,會發現調用哪個最終都會調用:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // 這裏是Handler與Message的綁定
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); //最終消息都會放入MessageQueue
}
Handler處理消息
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//我們從handleMessage點擊去繼續追蹤
}
};
消息最終由Looper取出,交給Handler的dispatchMessage進行處理
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message 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);
}
}
還記得 會調用ActivityThread的main函數嗎?調用了 Looper.loop();
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// 省略N行代碼................
Looper.prepareMainLooper(); // 看到這裏我們就明白了,
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 省略N行代碼................
Looper.loop();// 開始輪詢
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper.loop();
最終由Looper取出消息進行消息分發。
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;
/// 省略N行代碼...........
for (;;) {
Message msg = queue.next(); // might block
/// 省略N行代碼...........
try {
msg.target.dispatchMessage(msg); // 這裏調用了Handler的dispatchMessage進行消息分發
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
/// 省略N行代碼...........
}
}
附上消息分發流程圖:
注:如有什麼不對,理解不到位的麻煩各位看官指出!在下感激不盡。