簡要分析android中消息循環涉及到的幾個方法的源代碼(API19):
1 Handler構造方法
public Handler(Callback callback, boolean async)
{
//檢測Handler是否寫成匿名內部類的形式,是則提示這有可能導致內存泄露
//如果Handler寫成匿名內部類,當我們要銷燬它的外部類對象(通常爲Activity)時
//該外部類所處的線程中的messageQueue中的message持有handler,也就是匿名內部類對象本身的引用
//而匿名內部類持有外部類的引用
//如果messageQueue中有延遲時間很長的message,就會導致handler無法被銷燬,進而導致外部類(Activity等)無法被銷燬
//造成這個問題的本質原因是handler、looper、messageQueue是threadLocal設置的線程級變量
//其生命週期可能長於該線程中運行的Activity等外部類,而handler又被寫成了內部類
//導致內部類的生命週期長於外部類,阻止了外部類的銷燬
if (FIND_POTENTIAL_LEAKS){
final Class<? extendsHandler> klass = getClass();
if((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass())&&
(klass.getModifiers() &Modifier.STATIC) == 0) {
Log.w(TAG, "Thefollowing Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//取得當前線程的looper
mLooper = Looper.myLooper();
//當前線程沒有looper則報錯
if (mLooper == null) {
throw newRuntimeException(
"Can't create handlerinside thread that has not called Looper.prepare()");
}
//從當前線程的looper中取得MessageQueue的引用
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
//handler建立的時候就建立和取得了本線程的looper和messagequeue
}
2 Looper的myLooper()方法
public static Looper myLooper() {
//從當前looper的threadLocal線程本地變量中取出本線程擁有的looper
return sThreadLocal.get();
}
3 Looper的構造方法
//looper對象持有一個threadLocal對象,messageQueue
staticfinal ThreadLocal<Looper> sThreadLocal = newThreadLocal<Looper>();
private staticLooper sMainLooper;
finalMessageQueue mQueue;
finalThread mThread;
//Looper的構造方法是私有的,並且在構造的時候生成了MessageQueue
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}4 Looper的prepare()方法
//用該方法調用looper的構造方法創建looper
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get()!= null) {
throw newRuntimeException("Only one Looper may be created per thread");
}
//創建新的looper對象存入當前looper的threadLocal線程本地變量
sThreadLocal.set(new Looper(quitAllowed));
//使用threadLocal對象存儲looper保證了一個線程只有一個looper
//又因爲message Queue是在looper的構造方法中建立的,一個looper只有一個messageQueue
//這樣,線程、looper、messageQueue實現了一一對應
//但是,handler與上述三個部件不是一一對應的,一個線程的looper和messageQueue可以對應多個handler
}
5 Looper的loop()方法
//用該方法取得當前線程的looper並啓動其消息循環
public static void loop() {
//取得當前線程的looper
final Looper me = myLooper();
if (me == null) {
throw newRuntimeException("No Looper; Looper.prepare() wasn't called on thisthread.");
}
//取得當前線程的MessageQueue
final MessageQueue queue = me.mQueue;
// Make sure the identity of thisthread is that of the local process,
// and keep track of what that identitytoken actually is.
Binder.clearCallingIdentity();
final long ident =Binder.clearCallingIdentity();
//開啓一個死循環,從messageQueue中取出下一條消息,取出的動作可能是阻塞的
for (;;){
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates thatthe message queue is quitting.
return;
}
// This must be in a localvariable, 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);
}
//將從messageQueue中取得的消息發送給該消息指定的handler去處理
msg.target.dispatchMessage(msg);
if (logging != null){
logging.println("<<<<< Finished to " +msg.target + " " + msg.callback);
}
// Make sure that during the courseof dispatching the
// identity of the thread wasn'tcorrupted.
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);
}
//handler處理完消息後將其回收
msg.recycle();
}
}
6 MessageQueue的的next()方法
//從messageQueue中取出下一個消息
Message next() {
......................
//在取消息時用同步鎖鎖住messageQueue,防止不同線程的 handler同時操作messageQueue
synchronized (this) {
// Try to retrieve the nextmessage. Return if found.
final long now =SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//從前向後遍歷鏈表,找到第一個異步(其它線程發來的)消息
if (msg != null && msg.target == null) {
// Stalled by abarrier. Find the next asynchronousmessage in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null &&!msg.isAsynchronous());
}
//由於messageQueue的enqueueMessage()方法在將message插入消息鏈表的時候根據消息的執行時間進行了排序
//所以之前找到的第一個異步消息一定是執行時間最早的異步消息
if (msg!= null) {
//如果當前時間早於執行時間最早的異步消息的執行時間,不執行
if (now < msg.when) {
// Next message is notready. Set a timeout to wake up when itis ready.
nextPollTimeoutMillis =(int) Math.min(msg.when - now, Integer.MAX_VALUE);
//如果當前時間晚於執行時間最早的異步消息的執行時間,返回這個異步消息給looper
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null){
prevMsg.next =msg.next;
} else {
mMessages =msg.next;
}
msg.next = null;
if (false)Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
................................
}
7 MessageQueue的enqueueMessage()方法
boolean enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {
throw newAndroidRuntimeException(msg + " This message is already in use.");
}
if (msg.target == null) {
throw newAndroidRuntimeException("Message must have a target.");
}
synchronized (this) {
if (mQuitting) {
RuntimeException e = newRuntimeException(
msg.target + " sending messageto a Handler on a dead thread");
Log.w("MessageQueue",e.getMessage(), e);
return false;
}
msg.when = when;
Message p = mMessages;
boolean needWake;
//按照message自帶的執行時間將message插入到消息鏈表中,執行時間早的插入到靠前的位置
if (p ==null || when == 0 || when < p.when) {
// New head, wake up the eventqueue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middleof the queue. Usually we don't have towake
// up the event queue unlessthere is a barrier at the head of the queue
// and the message is theearliest 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 becausemQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
8 Handler的dispatchMessage()方法
//looper調用handler的此方法,將messageQueue中取出的message傳給此方法
//此方法按優先級依次查找三種方法來處理message,找到就結束,找不到再去找下一個優先級的方法
//優先級1:message自己指定的處理方法
//優先級2:handler在構造時傳入的Handler.Callback接口的實現對象所重寫的handleMessage()方法
//優先級3:handler被覆蓋的handleMessage()方法
public void dispatchMessage(Message msg) {
if (msg.callback != null){
handleCallback(msg);
} else {
if (mCallback != null){
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
------------------------------------------------------我是分割線-----------------------------------------------------------------------------看過了上面幾個跟消息循環有關的方法,我們可以總結一下一個消息從生到死的全過程啦:
消息循環流程:
0. Looper類中有一個靜態成員變量threadLocal對象
1. Looper.prepare():
(Looper類的靜態方法)
構造looper對象,looper對象在構造時構造messageQueue對象,
用Looper類的靜態threadLocal對象將構造出來的looper對象設定爲線程級變量
2. Handler handler = new Handler(){ @Override public void handleMessage(Messagemsg){.........}}
構造Handler繼承類的對象,重寫其handleMessage()方法
構造時調用Looper類的靜態方法myLooper()從Looper類的靜態threadLocal對象中取得當前線程所擁有的looper對象
此時handler擁有了當前線程的looper和messageQueue對象
3. Looper.loop()
(Looper類的靜態方法)
調用Looper類的靜態方法myLooper()從Looper類的靜態threadLocal對象中取得當前線程所擁有的looper對象,
開啓死循環不停地調用messageQueue的next()方法以阻塞方式從剛纔取得的looper對象中包含的messageQueue中獲取下一個message
將獲取的message傳給message的target所指定的handler的dispatchMessage()方法
後者依據優先級調用Handler.Callback或者handler類方法的handleMessage()來處理消息
4. handler.sendMessage(Message msg):
將傳入message的target設定成自己
調用當前線程的messageQueue的enqueueMessage()方法將傳入的message按照message執行時間先後順序插入messageQueue
5. 第3步和第4步同時進行
handler.sendMessage(Messagemsg)通過調用messageQueue的enqueueMessage()將消息加入消息隊列
Looper.loop()通過messageQueue的next()方法將消息從消息隊列中取出,發給其指定的handler的handleMessage()方法處理