問(wèn)題
Handler. post(Runnable r)的消息是如何傳遞的,傳遞了什么消息摧冀。
Post內(nèi)部將r對(duì)象轉(zhuǎn)化為消息發(fā)送到Handler所在線程的消息隊(duì)列中,執(zhí)行Looper.loop()方法的線程,將直接執(zhí)行r中的run()方法(注意沒(méi)有開啟新線程宗挥,而是在Handler所在的線程中執(zhí)行的r中的run()方法)Handler在哪個(gè)線程創(chuàng)建乌庶,就在哪個(gè)線程運(yùn)行handleMessage(Message msg)。如何實(shí)現(xiàn)的綁定契耿。
Looper.prepare()方法中將出初始化一個(gè)線程池瞒大,它能保證Looper與當(dāng)前線程一一對(duì)Looper的運(yùn)行機(jī)制
Looper.prepare()方法中進(jìn)行了線程池的初始化、創(chuàng)建消息隊(duì)列并將消息放在消息隊(duì)列中等操作(其中msg.targe屬性保存了Handler的對(duì)象)搪桂,在調(diào)用Looper.loop()方法從消息隊(duì)列中取消息并調(diào)用Handler的dispatchMessage(Message msg)方法透敌,在該方法中執(zhí)行handleMessage(Message msg)方法處理消息主線程如何利用Handler消息機(jī)制運(yùn)行handleMessage(Message msg)。
在創(chuàng)建Handler對(duì)象的線程中踢械,Looper.loop()方法調(diào)用了Handler的dispatchMessage(Message msg)方法酗电,在該方法中執(zhí)行了handlemessage(Message msg)主線程的Looper在哪定義的,handleMessage(Message msg)如何運(yùn)行到主線程中的内列。
ActivityThread的main()方法中首先執(zhí)行了Looper.prepare()方法撵术,并在main()方法的最后執(zhí)行了Looper.loop()方法(該方法中執(zhí)行了handleMessage(Message msg)方法)
Handler的創(chuàng)建
Handler的默認(rèn)構(gòu)造方法如下:
public Handler() {
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 = null;
}
在Handler中沒(méi)有看到與當(dāng)前線程相關(guān)的綁定操作,唯一可能與此有關(guān)的便是mLooper = Looper.myLooper();這一句话瞧。于是查看Looper.myLooper()方法嫩与,其代碼如下:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static Looper myLooper() {
return sThreadLocal.get();
}
這里主要用到的就是一個(gè)ThreadLocal,ThreadLocal是在Java.lang包里定義的一個(gè)工具類移稳,其主要功能是為本地所有線程保存一個(gè)數(shù)據(jù)蕴纳。ThreadLocal保證每個(gè)線程之間的數(shù)據(jù)相互獨(dú)立,一個(gè)線程相關(guān)數(shù)據(jù)的改變不會(huì)影響其他的線程數(shù)據(jù)个粱。
在Looper類中古毛,當(dāng)ThreadLocal被有效初始化后,myLooper()方法將能夠有效的獲取當(dāng)前線程所對(duì)應(yīng)的Looper對(duì)象都许。那么Looper的靜態(tài)方法能夠通過(guò)其所執(zhí)行的線程方便的獲取此線程相關(guān)的Looper對(duì)象稻薇,使得Looper類使用各靜態(tài)方法便能夠獲得與使用其對(duì)象一樣方便的使用方式。
ThreadLocal的初始化在Looper.prepare()中進(jìn)行胶征。
在Looper. prepare()中將當(dāng)前線程相關(guān)的唯一的一個(gè)Looper對(duì)象與當(dāng)前線程進(jìn)行相關(guān)聯(lián)塞椎,其代碼如下:
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));
}
因此,在使用Looper之前進(jìn)行prepare()(里面有ThreadLocal的初始化操作)將保證當(dāng)前線程擁有并只有一個(gè)Looper的對(duì)象與之相對(duì)應(yīng)睛低,在Handler創(chuàng)建時(shí)將獲取與此Handler想對(duì)應(yīng)的Looper案狠。
至此,Handler與執(zhí)行線程的問(wèn)題解決钱雷。
Looper的運(yùn)行
雖然解決了Handler與線程以及Looper之間的關(guān)聯(lián)關(guān)系骂铁,但HandleMessage()究竟如何被相關(guān)線程執(zhí)行的問(wèn)題仍然沒(méi)有得到解決。
在Looper的API文檔中有如下記述:
一個(gè)典型的Looper線程如下所示罩抗。
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();
}
}
在執(zhí)行handleMessage(Message msg)線程中應(yīng)先執(zhí)行Looper.prepare()方法拉庵,并創(chuàng)建Handler對(duì)象,最后執(zhí)行Looper.loop()方法套蒂。因此钞支,handleMessage(Message msg)方法應(yīng)該在Looper.loop()方法中以某種方式運(yùn)行茫蛹。
Looper.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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycle();
}
}
注意:調(diào)用loop()方法的線程與創(chuàng)建Handler對(duì)象的線程是同一線程∷感或者說(shuō)婴洼,Handler創(chuàng)建的線程在沒(méi)有改變其指向的情況下,只能由該線程的loop()方法來(lái)處理傳遞給Handler的消息信夫。
在通過(guò)myLooper()方法獲取了當(dāng)前線程對(duì)應(yīng)的Looper對(duì)象me后窃蹋,使用me獲取了當(dāng)前線程所對(duì)應(yīng)的MessageQueue。然后進(jìn)入了一個(gè)由for定義的死循環(huán)静稻。
在獲取了即將要處理的Massage msg后警没,執(zhí)行了msg.target.dispatchMessage(msg)。
msg.target是定義在Massage中的成員變量振湾,類型為Handler杀迹。指代此Message應(yīng)該由哪個(gè)Handler處理。因此押搪,當(dāng)msg.target.dispatchMessage(msg)被執(zhí)行树酪,將執(zhí)行此Message所對(duì)應(yīng)的Handler的dispatchMessage(Message msg)方法。
Handler中dispatchMessage(Message msg)方法定義如下:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
在不考慮msg擁有callback的情況下大州,要么執(zhí)行Handler的Callback接口中的handleMessage(msg)续语,要么執(zhí)行Handler復(fù)寫的handleMessage(msg)。
至此厦画,handleMessage(Message msg)方法的調(diào)用地點(diǎn)可以確定疮茄。應(yīng)該是在與Handler對(duì)象創(chuàng)建的同一線程中,由其后的Looper.loop()方法進(jìn)行的調(diào)用根暑。
主線程中的Looper
在正常編程的情況下力试,通常遇到的都是Activity的onCreate()方法、onStart()方法排嫌、onDestroy()方法等畸裳,他們就代表的主線程的使用,在這些方法中進(jìn)行UI界面的修改是被允許的淳地,但主線程究竟是如何調(diào)用Looper.loop()的卻不得而知怖糊,因此需要查找Activity的實(shí)際啟動(dòng)地點(diǎn)才能得知主線程的真實(shí)樣貌及Looper.loop()方法調(diào)用位置。
在android.app包中查找ActivityThread類颇象,其中在其源代碼最后定義了如下方法:
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
在看到main方法的定義后蓬抄,終于看到了Activity主線程的真實(shí)面目。這里對(duì)Looper進(jìn)行了當(dāng)前主線程的prepare并且在main方法的最后執(zhí)行了Looper.loop()方法夯到,實(shí)現(xiàn)對(duì)當(dāng)前線程Handler.HandleMessage(Message msg)的調(diào)用。
至此饮亏,主線程的Handler.HandleMessage(Message msg)的調(diào)用問(wèn)題解決耍贾。
Handler. post(Runnable r)
關(guān)于pos()t方法究竟做了些什么阅爽,怎么以一個(gè)Runnable接口當(dāng)做Message消息發(fā)送給其它線程以及如何執(zhí)行。這些問(wèn)題還需要查看Handler. post(Runnable r)的源代碼荐开,其源代碼如下:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
根據(jù)源代碼所述付翁,其post()方法也是通過(guò)某種形式將Runnable轉(zhuǎn)換為Message進(jìn)行消息的發(fā)送。而消息的獲取方式為getPostMessage(r)晃听,同時(shí)Runnable接口也是在這個(gè)方法中進(jìn)行處理的百侧。getPostMessage(Runnable r)方法定義如下:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
其中Message.obtain()是在消息池中獲取一條新的消息,即消息本身是空的能扒。而Runnable接口r緊緊是將其設(shè)置給剛剛創(chuàng)建的新消息m的callback佣渴。
在獲取了消息并設(shè)置了callback后就用將這條消息send給消息隊(duì)列。這條消息的處理同樣在Looper.loop()方法中調(diào)用了Handler的dispatchMessage(Message msg)初斑。再次給出dispatchMessage(Message msg)方法的代碼:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
可以看到辛润,當(dāng)msg.callback非空時(shí),將會(huì)調(diào)用handleCallback(msg)见秤。一下給出handleCallback(Message message)的代碼:
private static void handleCallback(Message message) {
message.callback.run();
}
在handleCallback(Message message)中直接調(diào)用了callback的run()方法砂竖。即在Looper.loop()方法執(zhí)行的線程中,直接執(zhí)行了Runnable所定義的線程鹃答。需要注意的是乎澄,這里并沒(méi)有啟動(dòng)新的線程來(lái)運(yùn)行Runnable接口,而是在Handler所在的線程中運(yùn)行测摔。