作過windows GUI的同窗應該清楚,通常的GUI操做都是基於消息機制的,應用程序維護一個消息隊列,開發人員編寫對應事件的回調函數就能實現咱們想要的操做java
其實android系統也和windows GUI同樣,也是基於消息機制,今天讓咱們經過源碼來揭開android消息機制的神祕面紗android
談起異步消息,就不能不說起Handler,在安卓中,因爲主線程中不能作耗時操做,因此耗時操做必須讓子線程執行,並且只能在主線程(即UI線程)中執行UI更新操做,經過Handler發送異步消息,咱們就能更新UI,通常的handler的用法以下:windows
public class TestActivity extends Activity { private Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); final TextView tv = (TextView) findViewById(R.id.textView); //建立一個handler對象,重寫handleMessage回調函數,在回調函數裏面作UI更新操做 mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0x1: //在這裏更新UI Bundle b = msg.getData(); tv.setText(b.getString("textview")); break; default: break; } } }; new Thread(new InnerRunnable()).start(); } private class InnerRunnable implements Runnable { @Override public void run() { //作耗時操做放在這裏 //建立一個消息對象 Message msg = Message.obtain(); msg.what = 0x1; //能夠用Bundle傳遞數據 Bundle b = new Bundle(); b.putString("textview", "異步加載"); mHandler.sendMessage(msg); } } }
咱們簡要概括一下Handler的常規使用方法:app
一、在UI線程建立Handler對象,並重寫handler的handlerMessage回調函數,能夠在回調函數裏面作UI更新操做異步
二、子線程完成耗時操做後,建立Message對象,用Message對象保存結果async
三、在子線程經過handler對象調用sendMessage函數發送消息,這樣UI線程收到消息後,獲取數據,就能夠更新UIide
是否是很簡單,那如今讓咱們一步一步來撥開迷霧,看清android異步消息本質函數
先簡要介紹會涉及的組件:oop
Handler:消息發送者ui
Looper:消息循環,負責從MessageQueue獲取消息,並處理
Message: 消息,能夠存放數據
MessageQueue : 消息隊列,負責存/取消息
從上面的例子咱們得知,要使用Handler必需要先在UI線程建立一個Handler對象,那麼咱們經過源碼查看Handler構造函數,代碼位於: com.google.android / android/os/Handler.java,(由於源碼較多,因此如下代碼截圖只包含關鍵代碼)
public class Handler { final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger; public Handler() { this(null, false); } 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()); } } 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使用了無參構造函數版本,但內部最終調用了Handler(Callback callback, boolean async)構造函數
在Handler(Callback callback, boolean async)代碼開始,先檢查FIND_POTENTIAL_LEAKS開關(該開關默認關閉),若該開關打開,則檢查Handler所在類是否爲匿名類/成員類或局部類時,而且該類是不是static的,若是不是static的,則輸出Log提示使用者Handler類不爲static可能會致使內存泄露,至於爲何會形成內存泄露,這裏先賣個關子
調用Looper.myLooper()獲取Looper對象,而後經過mQueue = mLooper.mQueue和Looper對象中的消息隊列關聯
那麼跟進Looper.myLooper看看,代碼位於: com.google.android / android/os/Looper.java
public final class Looper { static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; 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)); } public static Looper myLooper() { return sThreadLocal.get(); } private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); } }
Looper.myLooper()僅僅是返回一個線程副本,從代碼得知,實際建立Looper對象的函數爲Looper.paepare(),該函數建立Looper對象後存放到線程本地存儲
Looper的構造函數爲private,咱們只能經過Looper.myLooper獲取Looper對象,而建立Looper對象時,會建立一個消息隊列
這樣咱們如今明白了handler建立相關的工做,如今讓咱們來看看子線程發送消息的處理機制
當子線程發送傳遞消息時,調用了handler對象的sendMessage函數
public class Handler { final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger; 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); } return queue.enqueueMessage(msg, uptimeMillis); } }
根據上面的調用關係鏈:sendMessage->sendMessageDelayed->sendMessageAtTime->enqueueMessage;能夠看到最終sendMessage最終只作了兩件事情:
一、經過msg.target = this把Message對象和當前Handler對象關聯
二、把消息放到handler中Looper對象的MessageQueue中
消費消息位於Looper.loop函數中
public final class Looper { public static void loop() { final Looper me = myLooper(); 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(); // 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); } 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(); } } }
Looper.loop函數:
一、經過 final Looper me = myLooper()獲取當前線程的Looper對象
二、消息循環中, 經過Message msg = queue.next()獲取隊列中的消息,若沒有消息則阻塞
三、調用msg.target.dispatchMessage(msg)處理消息
四、處理完畢後調用msg.recycle()回收消息
根據上面代碼可得知實際處理消息的是msg.target.dispatchMessage(msg),那咱們來看看msg.target究竟是什麼東西
public final class Message implements Parcelable { /*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; // sometimes we store linked lists of these things /*package*/ Message next; private static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); } public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } }
原來msg.target是一個handler對象,而最終調用的是handler的dispatchMessage函數來處理消息
public class Handler { final MessageQueue mQueue; final Looper mLooper; final Callback mCallback; final boolean mAsynchronous; IMessenger mMessenger; public interface Callback { public boolean handleMessage(Message msg); } public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } }
根據如下代碼能夠得知消息處理的步驟以下:
一、先判斷Message的callback對象是否爲空,不爲空則回調Message對象的callback對象的函數(能夠再建立Message時指定Callback)
二、若是建立Handler的Callback對象不爲空,那麼則調用Callback對象的handlerMessage函數
三、若沒指定Handler的Callback或者Handler中Callback對象的handlerMessage函數調用失敗,則回調handlerMessage,而這個handlerMessage函數正是咱們建立handler時重寫的函數
至此咱們明白安卓異步消息的內部機制:
一、子線程經過handler向UI線程Looper中MessageQueue發送message
二、Looper處理消息時再回調handler中定義的回調
至此用一張圖總結android異步消息機制(網上找的,湊合看):
因此要讓一個線程要想成爲消息處理線程,那麼必須得有Looper才行,可能此時你會疑惑,爲何UI線程沒有建立Looper卻也能接收Handler發送來的消息?
其實,APP初始化過程當中,android會自動幫UI線程建立Looper對象,代碼位於:com.google.android / android/app/ActivityThread.java
public final class ActivityThread { public static void main(String[] args) { SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); Security.addProvider(new AndroidKeyStoreProvider()); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } }
能夠看到調用了Looper.prepareMainLooper()爲主線程建立Looper,最後調用Looper.loop進行消息循環
經過分析源碼,能夠得知:
一、若是主線程和子線程,或者子線程同子線程通訊,能夠調用Looper.prepare()爲Looper.loop()爲子線程建立消息隊列,再經過handler就能夠很是簡單的實現線程間通訊
二、建立Message對象,必定要用Message.obtain()函數代替new Message()來建立消息,由於Looper處理完消息後,會調用 msg.recycle()函數把Message歸還到消息池中,使用Message.obtain會先從消息池中獲取,若沒有才會建立新的Message,這樣能夠避免重複建立Message對象
三、Handler所在類必須是static類,由於非static內部類會隱式的持有外部類的引用,假如延時操做還未執行完成時就關閉Activity,由於handler持有Activity的引用,那麼Activity就不會被及時回收而形成內存泄露