當啟動一個apk應用程式的時候,Android會開啟一個主線程(UI線程),由於主線程是非安全執行緒,當我們需要在主線程中操作大資料或者連網等這些耗時的操作時,會影響到Android UI的顯示並且會出現假死狀態,這對使用者的體驗來說是很不樂觀的。因此,我們需要把那些耗時的操作交給另外一個線程來處理,子線程將處理的結果返回給主線程,主線程根據得到的資料作出相應的操作。Handler就實現了這一機制。在Android中實現訊息處理的主要有:Handler、Message、Looper、MessageQueue這幾個類。我們來看看這幾個類內部到底是怎麼運轉的。
Looper.prepare初始化當前線程,看看都初始化了一些什麼。
public class Looper { private static final String TAG = "Looper"; static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//線程TLS private static Looper sMainLooper; final MessageQueue mQueue;//訊息佇列 final Thread mThread;//當前線程 volatile boolean mRun; private Printer mLogging; /** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ public static void prepare() { prepare(true); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); } private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) {//當前線程如果已經有Looper的時候則建立失敗,由此可見,一個線程只能有一個Looper throw new RuntimeException("Only one Looper may be created per thread"); }//建立Looper對象並儲存到當前線程的TLS sThreadLocal.set(new Looper(quitAllowed)); }}
就這樣Looper的初始工作已經完成了,然後就是迴圈監聽訊息。
public static void loop() { final Looper me = myLooper();//擷取當前線程的Looper if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue;//擷取當前線程的訊息佇列 Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();//這裡就是開始迴圈的地方,這是一個死迴圈,我記得2.x的版本是while(true),也許是考慮效率問題嘛。for(;;)效率要高些 for (;;) { Message msg = queue.next(); //擷取訊息 if (msg == null) { // No message indicates that the message queue is quitting. return; } Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); }//這裡就是把訊息交給handler來處理。由於一個線程可能有多個Handler對象發送訊息(Message)。//所以,每個Message對象儲存了自己的Handler。這樣Looper才知道到底要交給哪一個Handler來處理。 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); }//釋放message資源 msg.recycle(); } }
接下看,在看看Handler的實現過程。建構函式
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(); 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; }
Handler.sendMessage發送資料,最終使用的時enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {//設定message的target為當前Handler//與在Looper.loop() 裡面的 msg.target.dispatchMessage(msg) 相對應 msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
Handler.dispatchMessage接收資料
public void dispatchMessage(Message msg) {//msg.calllbak 是一個Runable,如果不為空白就執行run方法來處理這個message if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } }//否則調用我們自己現實handler的回呼函數 handleMessage(msg); } }
整個訊息的處理就到這裡了,一些細節的方面就在以後的項目中再來慢慢體會。