常見(jiàn)的使用Handler線程間通訊:
//主線程:
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
...
}
};
//子線程:
Message message = new Message();
message.arg1 = 1;
Bundle bundle = new Bundle();
bundle.putString("test", "test");
message.setData(bundle);
handler.sendMessage(message);
這類操作一般用于在子線程更新UI劈彪。在主線程創(chuàng)建一個(gè)handler竣蹦,重寫handlermessage方法,然后在子線程里發(fā)送消息沧奴,主線程里就會(huì)接受到消息痘括。這就是簡(jiǎn)單的線程間通訊。
如果在子線程創(chuàng)建handler對(duì)象則會(huì)報(bào)錯(cuò)滔吠。根據(jù)Log提示纲菌,子線程創(chuàng)建handler需要調(diào)用Looper.prepare() (在main函數(shù)中已經(jīng)調(diào)用了Looper.prepareMainLooper(),該方法內(nèi)會(huì)調(diào)起Looper.prepare())疮绷,Looper.loop()方法 翰舌。但是即使子線程調(diào)用Looper.prepare()創(chuàng)建Looper對(duì)象,這個(gè)Looper也是子線程的冬骚,不可以用于更新UI操作椅贱。
那到底Handler、Looper這幾個(gè)類之間是如何工作的呢只冻?我們從源頭看起庇麦,以下是Looper類的prepare()方法:
public final class Looper {
...
final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //threadLocal是線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類,該類存儲(chǔ)了線程的所有數(shù)據(jù)信息喜德。
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)); //創(chuàng)建一個(gè)Looper(Looper的構(gòu)造器里也創(chuàng)建了一個(gè)MessageQueue山橄,),將Looper與線程關(guān)聯(lián)起來(lái)
}
public static @Nullable Looper myLooper() { //下面會(huì)看到的舍悯,設(shè)置Handler類里的Looper時(shí)會(huì)調(diào)用該方法
return sThreadLocal.get(); //獲得Looper對(duì)象
}
...
}
當(dāng)handler傳輸message時(shí)航棱,不論是調(diào)用sendMessage(Message msg)還是sendMessageDelayed(),最后都會(huì)指向sendMessageAtTime()方法:
public class Handler {
...
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);
}
...
}
mQueue即消息隊(duì)列睡雇,用于將收到的消息以隊(duì)列形式排列,提供出隊(duì)和入隊(duì)方法饮醇,該變量是Looper的成員變量入桂,在Handler創(chuàng)建時(shí)賦值給handler
public class Handler {
...
final Looper mLooper;
final MessageQueue mQueue;
mLooper = Looper.myLooper(); //創(chuàng)建Handler前調(diào)用Looper.prepare()時(shí)定義并設(shè)置了Looper,這里調(diào)用Looper.myLooper()來(lái)獲得該Looper
mQueue = mLooper.mQueue;
...
}
上面調(diào)用的enqueueMessage(queue, msg, uptimeMillis)方法作用是消息入隊(duì)
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; //把handler本身賦值給要入隊(duì)的消息驳阎,用來(lái)待會(huì)兒出隊(duì)使用
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
可以看到最后是由消息隊(duì)列queue調(diào)用自身MessageQueue類的入隊(duì)方法enqueueMessage()
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
mMessages是MessageQueue類的一個(gè)成員變量,用以記錄排在最前面的消息馁蒂,msg是我們傳入的message呵晚,msg.next是Message類的成員變量,可以理解成下一條消息沫屡。入列方法重點(diǎn)看這幾句:
Message p = mMessages;
msg.next = p; //把mMessages賦值給新入隊(duì)的這條消息的next
mMessages = msg; //把新入隊(duì)的消息賦值給mMessages
就像排隊(duì)一樣饵隙,msg是來(lái)插隊(duì)的,排第一的mMessages自愿排到msg的后面沮脖,并讓msg站到自己原來(lái)的位置上金矛,這樣就完成的msg的入隊(duì)操作,整個(gè)消息入隊(duì)操作是按照時(shí)間來(lái)排序的。至于出隊(duì)操作勺届,就在一開(kāi)始所提到的ActivityTread中的main方法里調(diào)用的Looper.loop()方法里:
public static void loop() {
...
for (;;) {
...
Message msg = queue.next(); //獲取下一條消息
...
msg.target.dispatchMessage(msg); //傳遞消息
...
msg.recycleUnchecked(); //清空狀態(tài)驶俊,循環(huán)往復(fù)
}
}
...
}
提煉出來(lái)就是在loop方法里一直死循環(huán),從MessageQueue消息隊(duì)列里使用next()方法獲得下一條消息免姿,next方法簡(jiǎn)單看就是:
Message msg = mMessages;
mMessages = msg.next;
msg.next = null;
return msg;
這就是簡(jiǎn)單的解釋消息出列饼酿,把排第一的消息作為方法的返回值,然后讓排第二的排到第一去胚膊。獲得消息后使用msg.target(上面入隊(duì)時(shí)賦值的handler)來(lái)傳遞消息:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg); //如果有callback參數(shù)則調(diào)用處理回調(diào)的方法
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); //將消息作為參數(shù)傳遞出去
}
}
至此故俐,handler傳遞消息的整個(gè)流程走完。另外還有一個(gè)我們經(jīng)常用到handler的方法post:
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) { //將runnable變成message自身的callback變量
Message m = Message.obtain();
m.callback = r;
return m;
}
可以看到紊婉,post的runnable參數(shù)經(jīng)過(guò)getPostMessage()方法最后被賦值給要傳遞下去的消息的callback這個(gè)變量药版,等到消息出列時(shí),如果消息帶有callback參數(shù)則調(diào)用處理回調(diào)的方法handleCallback(msg)
private static void handleCallback(Message message) {
message.callback.run();
}
可以看到喻犁,不論是從sendMessage里發(fā)出的消息槽片,還是在post傳遞的runnable里執(zhí)行的代碼,最后都是殊途同歸株汉,都是在UI線程運(yùn)行的筐乳。最后總結(jié)一下吧,線程間通訊原理大概就是:
- Looper.prepare()創(chuàng)建Looper和MessageQueue乔妈,并與所在線程關(guān)聯(lián)
- Looper.loop()通過(guò)一個(gè)for死循環(huán)不斷對(duì)MessageQueue進(jìn)行輪詢
- 創(chuàng)建handler時(shí)蝙云,會(huì)把Looper和MessageQueue賦值給handler,將三者關(guān)聯(lián)起來(lái)路召。當(dāng)handler調(diào)用sendMessage傳遞消息勃刨,消息會(huì)被發(fā)送到Looper的消息隊(duì)列MessageQueue里
- 一旦loop()方法接收到消息波材,則將消息通過(guò)該消息攜帶的handler(msg.target)的handleMessage方法處理