轉載請注明出處:http://blog.csdn.net/singwhatiwanna/article/details/17361775
上周對android中的事件派發機制進行了分析,這次部落客要對消息隊列和looper的源碼進行簡單的分析。大家耐心看下去,其實消息隊列的邏輯比事件派發機制簡單多了,是以大家肯定會很容易看懂的。
消息隊列在android中對應messagequeue這個類,顧名思義,消息隊列中存放了大量的消息(message)
消息(message)代表一個行為(what)或者一串動作(runnable),有兩處會用到message:handler和messenger
handler大家都知道,主要用來線上程中發消息通知ui線程更新ui。messenger可以翻譯為信使,可以實作程序間通信(ipc),messenger采用一個單線程來處理所有的消息,而且程序間的通信都是通過發消息來完成的,感覺不能像aidl那樣直接調用對方的接口方法(具體有待考證),這是其和aidl的主要差別,也就是說messenger無法處理多線程,所有的調用都是在一個線程中串行執行的。messenger的典型代碼是這樣的:new messenger(service).send(msg),它的本質還是調用了handler的sendmessage方法
looper是循環的意思,它負責從消息隊列中循環的取出消息然後把消息交給目标處理
線程如果沒有looper,就沒有消息隊列,就無法處理消息,線程内部就無法使用handler。這就是為什麼在子線程内部建立handler會報錯:"can't create handler inside thread that has not called looper.prepare()",具體原因下面再分析。
線上程的run方法中加入如下兩句:
looper.prepare();
looper.loop();
這一切不用我們來做,有現成的,handlerthread就是帶有looper的線程。
想用線程的looper來建立handler,很簡單,handler handler = new handler(thread.getlooper()),有了上面這幾步,你就可以在子線程中建立handler了,好吧,其實android早就為我們想到這一點了,也不用自己寫,intentservice把我們該做的都做了,我們隻要用就好了,具體怎麼用後面再說。
一個handler會有一個looper,一個looper會有一個消息隊列,looper的作用就是循環的周遊消息隊列,如果有新消息,就把新消息交給它的目标處理。每當我們用handler來發送消息,消息就會被放入消息隊列中,然後looper就會取出消息發送給它的目标target。一般情況,一個消息的target是發送這個消息的handler,這麼一來,looper就會把消息交給handler處理,這個時候handler的dispatchmessage方法就會被調用,一般情況最終會調用handler的handlemessage來處理消息,用handlemessage來處理消息是我們常用的方式。
源碼分析
[java] view
plaincopy
public final boolean sendmessage(message msg)
{
return sendmessagedelayed(msg, 0);
}
public final boolean sendmessagedelayed(message msg, long delaymillis)
if (delaymillis < 0) {
delaymillis = 0;
}
return sendmessageattime(msg, systemclock.uptimemillis() + delaymillis);
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);
}
private boolean enqueuemessage(messagequeue queue, message msg, long uptimemillis) {
msg.target = this;
if (masynchronous) {
msg.setasynchronous(true);
//這裡msg被加入消息隊列queue
return queue.enqueuemessage(msg, uptimemillis);
public static void loop() {
final looper me = mylooper();
if (me == null) {
throw new runtimeexception("no looper; looper.prepare() wasn't called on this thread.");
}
//從looper中取出消息隊列
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);
//将消息交給target處理,這個target就是handler類型
msg.target.dispatchmessage(msg);
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();
}
/**
* 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) {
//這個方法很簡單,直接調用msg.callback.run();
handlecallback(msg);
} else {
//如果我們設定了callback會由callback來處理消息
if (mcallback != null) {
if (mcallback.handlemessage(msg)) {
return;
}
}
//否則消息就由這裡來處理,這是我們最常用的處理方式
handlemessage(msg);
我們再看看msg.callback和mcallback是啥東西
/*package*/ runnable callback;
現在已經很明确了,msg.callback是個runnable,什麼時候會設定這個callback:handler.post(runnable),相信大家都常用這個方法吧
/**
* callback interface you can use when instantiating a handler to avoid
* having to implement your own subclass of handler.
*
* @param msg a {@link android.os.message message} object
* @return true if no further handling is desired
public interface callback {
public boolean handlemessage(message msg);
final callback mcallback;
而mcallback是個接口,可以這樣來設定 handler handler = new handler(callback),這個callback的意義是什麼呢,代碼裡面的注釋已經說了,可以讓你不用建立handler的子類但是還能照樣處理消息,恐怕大家常用的方式都是新new一個handler然後override其handlemessage方法來處理消息吧,從現在開始,我們知道,不建立handler的子類也可以處理消息。多說一句,為什麼建立handler的子類不好?這是因為,類也是占空間的,一個應用class太多,其占用空間會變大,也就是應用會更耗記憶體。
@override
public void run() {
mtid = process.mytid();
looper.prepare();
synchronized (this) {
mlooper = looper.mylooper();
notifyall();
process.setthreadpriority(mpriority);
onlooperprepared();
looper.loop();
mtid = -1;
handlerthread繼承自thread,其在run方法内部為自己建立了一個looper,使用上handlerthread和普通的thread不一樣,無法執行常見的背景操作,隻能用來處理新消息,這是因為looper.loop()是死循環,你的code根本執行不了,不過貌似你可以把你的code放在super.run()之前執行,但是這好像不是主流玩法,是以不建議這麼做。
public void oncreate() {
// todo: it would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startservice(context, intent)
// method that would launch the service & hand off a wakelock.
super.oncreate();
handlerthread thread = new handlerthread("intentservice[" + mname + "]");
thread.start();
mservicelooper = thread.getlooper();
mservicehandler = new servicehandler(mservicelooper);
intentservice繼承自service,它是一個抽象類,其被建立的時候就new了一個handlerthread和servicehandler,有了它,就可以利用intentservice做一些優先級較高的task,intentservice不會被系統輕易殺掉。使用intentservice也是很簡單,首先startservice(intent),然後intentservice會把你的intent封裝成message然後通過servicehandler進行發送,接着servicehandler會調用onhandleintent(intent
intent)來處理這個message,onhandleintent(intent intent)中的intent就是你startservice(intent)中的intent,ok,現在你需要做的是從intentservice派生一個子類并重寫onhandleintent方法,然後你隻要針對不同的intent做不同的事情即可,事情完成後intentservice會自動停止。是以,intentservice是除了thread和asynctask外又一執行耗時操作的方式,而且其不容易被系統幹掉,建議關鍵操作采用intentservice。
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());
//擷取目前線程的looper
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;
如何避免這種錯誤:在ui線程使用handler或者給子線程加上looper。