先說說Looper類:Looper就是爲每個線程建立一個Looper對象,維護一個MessageQueue,並循環從MessageQueue中取出消息並分發給Handler執行。下面是Looper源碼中如何使用的一個示例數組
class LooperThread extends Thread {併發
* public Handler mHandler;ide
*函數
* public void run() {oop
* Looper.prepare();post
*ui
* mHandler = new Handler() {this
* public void handleMessage(Message msg) {spa
* // process incoming messages here線程
* }
* };
*
* Looper.loop();
* }
* }
咱們看看Looper.prepare幹了些什麼事
public static void prepare() {
prepare(true);
}
//判斷當前線程是否有Looper對象,沒有則new一個並放到ThreadLocal中
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));
}
至於這個地方爲何要用ThreadLocal來存儲Looper對象呢:
咱們知道ThreadLocal是與線程相關的一個類,系統規定每一個線程只能有一個Looper對象,也就是說只能由一個MessageQueue對象,這樣便於維護消息隊列。若是我已經prepare一次了,那麼個人當前線程中是有Looper對象的,並存儲在當前線程變量內。當你再在此線程prepare時,ThreadLocal對象會獲取當前線程是否有Looper對象,若是有,直接拋異常,這是系統所不容許的,
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
所以ThreadLocal用來存儲Looper對象,設計的真雞賊,不知道你們還有沒有別的方式來控制一個線程只有一個Looper對象。看到不少博客都說ThreadLocal是用來併發控制資源共享的,ThreadLocal存儲每一個線程對資源的副本,再次本人以爲純屬扯淡,你去看看ThreadLocal的例子,若是ThreadLocal存儲副本,你丫的把「主本」給我找出來?經過Looper就能夠看出來ThreadLocal只是存儲當前線程的相關變量。
建立完Looper對象,並初始化了MessageQueue對象,下面該進入不斷循環,取出消息了:
public static void loop() {
final Looper me = myLooper();//你看,每次都是myLooper獲取當前線程的Looper對象,省得獲取到別的線程的了
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(); // 從隊列中獲取下一個
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);
}
//獲取到消息以後分發給HAndler處理,其實這個Handler就是target
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();//回收Message對象,重複利用就在此,哈哈。。下面會講
}
}
至此,Looper的主要工做講完了。
接着是Message,就是攜帶了一些數據,被handler帶着飛。重複利用問題以及鏈表的結構。
先看看都帶了什麼數據:
/*package*/ int flags;
/*package*/ long when;//時間而已
/*package*/ Bundle data;//數據
/*package*/ Handler target; //Handler,代表我這個Message要被哪一個Handler處理,固然是誰發送我,誰處理,發送個人時候給我賦值
/*package*/ Runnable callback; //post(Runnable r)函數使用
// sometimes we store linked lists of these things
/*package*/ Message next;//連接下一個Message
再看看重複利用:
public void recycle() {
clearForRecycle();//把要回收的這個Message數據清空
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {//不超過50個,源碼的常量
next = sPool;
sPool = this;//關鍵在這,又把這個對象賦給了靜態的sPool引用,gc不會回收此Message
sPoolSize++;
}
}
}
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
看吧,咱們obtain的時候會利用剛纔回收掉的Message,不然才new Message();
再看MessageQueue,他裏面並不真正的使用數組的形式去存儲一系列的Message,而是經過Message的next使用鏈表的形式維護Message隊列,只要能拿到鏈表的第一個Message就能夠展開一系列的循環讀取Message。經過next()方法獲取。代碼就不貼了。
最後是Handler類介紹:建立一個Handler對象,通常都會重寫handleMesage方法。去處理咱們發送過來的消息,handleMessage什麼時候被調用呢,看下
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);//處理handler.post(Runnable r)的
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//調用了吧
}
}
那麼dispatchMessage的調用呢,看前面的Looper.loop(),娶到一個Message以後,經過Message 的target(Handler)調用到的,這樣處理的過程。
再看看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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//這個很重要就是把此Handler對象直接賦給此Message的target,
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//這個就是把此Message對象加入MessageQueue
}
這樣,整個流程就走完了,發送到加入隊列,再取,在處理的流程。
發送是Handler,加入隊列是MessageQueue,取是Looper(內部也是MesageQueue取的,不過是有Looper維護此隊列而已),處理是Handler。
Activity主線程,在程序中的main方法已經prepare了,而且loop了,因此咱們不必建立Looper對象。
在咱們本身建立的子線程中,咱們要想處理消息,必須Looper.prepare,而且loop()。