轉載請聲明出處:http://blog.csdn.net/qq_24692041/article/details/68066025
Android線程間通訊方式有很多,但是大部分內部實現其實都是handler。今天我們就來看看handler的內部實現機制,實現原理,實現細節。本文主要是爲了搞清楚線程間的通訊,Message也可以用於進程間的通訊,在本文中不對此進行詳細的講解,淺嘗輒止!後面如果有需要,我會補上Message的進程間通訊相關文章,敬請期待!
本文我們分步驟對Handler消息機制進行分析,這樣有條理一點,已更利於閱讀。
- 角色分析:
Handler進程間通訊主要關聯了Thread,ThreadLocal,Handler,Message,MessageQueue,Looper,,這幾個類在內。我們先看看這幾個類各自在這個實現工程中扮演者什麼樣的角色!
Thread:整個機制產生的意義,所有這個機制就是爲Thread服務!Looper的創建是爲Thread而創建,其實是Thread持有。Handler使用的Looper是由Thread提供!
ThreadLocal:Thread屬性的存儲者,內部維護一個ThreadLocalMap,其中存放了Thread的所有屬性,Looper就是存放在這兒。
Handler:消息的發起者,發出一個消息。消息的處理者,消息處理的時間到了對該消息進行處理。必須有一個Looper,通過操作Looper持有的MessageQueue實現消息的發送,當Looper通知處理Message的時候,對Message進行處理。
Message:數據和信號攜帶者,攜帶數據進行傳遞。處理時機決定者,通過when屬性決定消息的處理時間。消息隊列的產生者,將一個個的message對象串聯起來,形成消息隊列。
MessageQueue:消息存放者,存放了一個消息隊列,有消息進來的時候安插在指定的位置,需要處理的時候將消息取出來。消息排隊者,將消息按處理的時間進行存放,讓消息排隊進行處理。
Looper:運行機制全局掌控者,讓整個機制活動起來的關鍵人員,將所有角色聯繫起來,根據具體實現進行調度,完成整個機制的任務。內部持有一個MessageQueue,
Handler通過關聯Looper,聯繫上MessageQueue。
- 大體的運轉結構
瞭解了這些類在整個任務中充當的角色何彼此之間的聯繫之後,我們來看看他們大體都做了些什麼工作,讓整個機制運轉起來。
Handler通過sendMessage方法,將Message發送出去,MessageQueue通過queueMessage方法將消息存插入到消息隊列中等待被處理。Looper通過loop方法在特定的時間到MessageQueue中將消息取出來,回調Handler的dispatchMessage方法將消息交給Handler處理。
- 具體爲什麼就將數據在線程之間傳遞成功了呢?
通過第2點,我們大體瞭解了整個機制的原理,但是這樣做爲什麼就能實現線程間數據的傳遞呢?這個問題很關鍵,在我們源代碼分析完了之後再來進行講解,這兒先不說。
- 源代碼剖析:
下面我們對源代碼進行剖析,然後再來看看上面提到的理論和問題,整個消息機制就完全理解掌握了!
- Handler源碼分析:
public class Handler { private static final boolean FIND_POTENTIAL_LEAKS = false; private static final String TAG = "Handler"; //當前handler所在線程的looper final Looper mLooper; //跟looper對應的消息隊列 final MessageQueue mQueue; //處理消息的回調 final Callback mCallback; //決定處理消息的方式同步的還是異步的 final boolean mAsynchronous; IMessenger mMessenger; /** * 通過設置這個接口去處理消息,就不需要再定義一個Handler的子類 */ public interface Callback { public boolean handleMessage(Message msg); } /** * Subclasses must implement this to receive messages. * Message和Handler都沒有callback纔會調用處理消息,這兒啥也沒做,留着口給子類去完成了 */ public void handleMessage(Message msg) { } /** * 處理系統消息 * Handle system messages here. */ public void dispatchMessage(Message msg) { //如果msg有回調就交給msg處理 if (msg.callback != null) { handleCallback(msg); } else { //msg沒有回調,創建Handler的時候有給回調就交給這個回調處理 if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } //調用自己的handleMessage方法處理,什麼也沒做,交給子類去具體實現,具體操作。平時我們用的匿名內部類的方式就是走了這一步 handleMessage(msg); } } public Handler() { this(null, false); } /** * 構造方法,設定消息處理回調,如果當前線程中沒有Looper的時候,將接不到消息,還會拋出異常 */ public Handler(Callback callback) { this(callback, false); } /** * 構造方法,指定一個Looper,用這個Looper替換默認的Looper */ public Handler(Looper looper) { this(looper, null, false); } public Handler(Looper looper, Callback callback) { this(looper, callback, false); } /** * 設定當前Handler是同步處理消息還是異步處理消息 */ public Handler(boolean async) { this(null, async); } /** * 構造方法,初始化 */ 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,UI線程系統自動調用prepareMainLooper方法,創建了UI線程的looper //如果Handler在子線程中創建,必須先調用prepare創建一個looper,否則myLooper返回的是null,會拋出異常 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; } /** * 構造方法,初始化。跟2個參數的構造方法的區別是,這兒直接給定了looper */ public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; } /** * 獲取trace文件的名字,ANR分析的時候有用 */ public String getTraceName(Message message) { final StringBuilder sb = new StringBuilder(); sb.append(getClass().getName()).append(": "); if (message.callback != null) { sb.append(message.callback.getClass().getName()); } else { sb.append("#").append(message.what); } return sb.toString(); } /** * 獲取消息的名稱,用消息的callback類名或者what的十六進制命名 * * @param message The message whose name is being queried */ public String getMessageName(Message message) { if (message.callback != null) { //如果規定了message的回調,返回該回調類的名字 return message.callback.getClass().getName(); } //如果message沒有指定回調,返回what的十六進制 return "0x" + Integer.toHexString(message.what); } /** * 從消息池中獲取一個回收的message對象返回, * 但是這個message的處理handler是調用該方法的handler * 這樣效率比直接new一個Message要好 * 如果不想處理消息的handler被指定爲調用的handler可以調用Message.obtain方法 */ public final Message obtainMessage() { return Message.obtain(this); } /** * 跟上面的方法差不多,只是多了一點,指定了message的what變量值 */ public final Message obtainMessage(int what) { return Message.obtain(this, what); } public final Message obtainMessage(int what, Object obj) { return Message.obtain(this, what, obj); } public final Message obtainMessage(int what, int arg1, int arg2) { return Message.obtain(this, what, arg1, arg2); } public final Message obtainMessage(int what, int arg1, int arg2, Object obj) { return Message.obtain(this, what, arg1, arg2, obj); } /** * 將一個Runnable放到消息隊列中,處理的時候是由當前handler依附的線程處理 */ public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } /** * 跟上面的方法一樣,只是多了一個執行的時間指定,會在(uptimeMillis)這段時間過後才執行 */ public final boolean postAtTime(Runnable r, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r), uptimeMillis); } public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); } public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); } public final boolean postAtFrontOfQueue(Runnable r) { return sendMessageAtFrontOfQueue(getPostMessage(r)); } public final boolean runWithScissors(final Runnable r, long timeout) { if (r == null) { throw new IllegalArgumentException("runnable must not be null"); } if (timeout < 0) { throw new IllegalArgumentException("timeout must be non-negative"); } if (Looper.myLooper() == mLooper) { r.run(); return true; } BlockingRunnable br = new BlockingRunnable(r); return br.postAndWait(this, timeout); } /** * 移除消息隊列中所有待處理的任務 */ public final void removeCallbacks(Runnable r) { mQueue.removeMessages(this, r, null); } /** * Remove any pending posts of Runnable <var>r</var> with Object * <var>token</var> that are in the message queue. If <var>token</var> is null, * all callbacks will be removed. */ public final void removeCallbacks(Runnable r, Object token) { mQueue.removeMessages(this, r, token); } /** * 將消息push到消息隊列的隊尾,輪到處理該消息的時候會回調handleMessage去處理 * 如果push成功返回true,如果這個消息隊列已經exiting,將會push失敗,返回false */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } /** * 將一個沒有攜帶數據,只有what值的空消息push到消息隊列中 */ public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } /** * 將一個沒有攜帶數據,只有what值的空消息push到消息隊列中,但是會在特定的時間過後才能被delivered */ public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } /** * 將一個消息放入隊列,在當前時間+delayMillis(比如:一個小時之後處理,現在是12點,那就是12:00+1*60*60*1000) * 時間點之前應該要處理的消息全部處理完了之後,會在當前handler依附的線程中處理該消息。 * 這個消息將被傳到handleMessage方法中 */ public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } /** * 將一個消息放入消息隊列,在uptimeMillis(比如13:00)這個絕對時間點之前應該處理的消息處理完成之後會處理該消息 */ 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); } /** * 講一個消息放在隊首,這個方法一般不會使用,需要在特定的情況下使用。因爲這個方法可能會導致 * 消息隊列的排序出現問題,或者一些無法想象的異常出現 */ public final boolean sendMessageAtFrontOfQueue(Message msg) { 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, 0); } /** * 將消息放入隊列中,在uptimeMillis(13:00)處理這個消息 * * @param queue 將消息放入這個消息隊列 * @param msg 想要處理的消息 * @param uptimeMillis 處理的絕對時間點 * @return */ private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { //指定處理該消息的handler爲當前調用的handler msg.target = this; if (mAsynchronous) { //將消息設置爲可異步 msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); } /** * 從消息隊列中移除指定what值的,未處理的消息.移除之後這些消息對象會被回收,將不會被取出執行 */ public final void removeMessages(int what) { mQueue.removeMessages(this, what, null); } /** * 從消息隊列中移除指定what,和obj值,並且未處理的消息,移除之後這些消息對象會被回收,將不會被取出執行 */ public final void removeMessages(int what, Object object) { mQueue.removeMessages(this, what, object); } /** * 從消息隊列中移除所有指定obj值,並且未處理的消息和任務,移除之後這些消息對象會被回收,將不會被取出執行 */ public final void removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this, token); } /** * 查詢消息隊列中是否有跟指定what值的消息 */ public final boolean hasMessages(int what) { return mQueue.hasMessages(this, what, null); } /** * Check if there are any pending posts of messages with code 'what' and * whose obj is 'object' in the message queue. */ public final boolean hasMessages(int what, Object object) { return mQueue.hasMessages(this, what, object); } /** * 查詢消息隊列中是否有指定任務 */ public final boolean hasCallbacks(Runnable r) { return mQueue.hasMessages(this, r, null); } // if we can get rid of this method, the handler need not remember its loop // we could instead export a getMessageQueue() method... public final Looper getLooper() { return mLooper; } public final void dump(Printer pw, String prefix) { pw.println(prefix + this + " @ " + SystemClock.uptimeMillis()); if (mLooper == null) { pw.println(prefix + "looper uninitialized"); } else { mLooper.dump(pw, prefix + " "); } } @Override public String toString() { return "Handler (" + getClass().getName() + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}"; } ...... }
- Message源碼分析:
public final class Message implements Parcelable { /** * 用於指定當前消息的身份 */ public int what; /** * 該消息所攜帶的簡單數據 */ public int arg1; /** * 消息所攜帶的簡單數據 */ public int arg2; /** * 一個Object類型的數據,這個數據可以用於進程間數據傳遞,這兒不深究 */ public Object obj; /** * Optional Messenger where replies to this message can be sent. The * semantics of exactly how this is used are up to the sender and * receiver. */ public Messenger replyTo; /** * 通過 {@link Messenger}進行進程間數據傳遞的時候纔會有效,代表發送消息的進程的UID,一般情況下爲-1,這兒同樣不進行深究; */ public int sendingUid = -1; /** * 用於標誌當前消息是否正在使用 */ /*package*/ static final int FLAG_IN_USE = 1 << 0; /** * 用於標誌當前消息的同步和異步 */ /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1; /** * Flags to clear in the copyFrom method */ /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE; /*package*/ int flags; /*package*/ long when; /*package*/ Bundle data; /** * 處理該消息的handler */ /*package*/ Handler target; /** * 處理消息的回調,如果沒有這個回調將會調用Handler的handleMessage方法進行處理 */ /*package*/ Runnable callback; /** * 保存了下一個message對象的地址 */ /*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; private static boolean gCheckRecycle = true; /** * 從消息池中獲取一個message對象返回,避免過多創建對象 */ public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); } /** * 從消息池中獲取一個message對象返回,避免過多創建對象 * 並且將傳進來的消息中的數據複製給message,並返回 */ public static Message obtain(Message orig) { Message m = obtain(); m.what = orig.what; m.arg1 = orig.arg1; m.arg2 = orig.arg2; m.obj = orig.obj; m.replyTo = orig.replyTo; m.sendingUid = orig.sendingUid; if (orig.data != null) { m.data = new Bundle(orig.data); } m.target = orig.target; m.callback = orig.callback; return m; } /** * 從消息池中獲取一個message對象返回,避免過多創建對象 * 指定一個handler去處理 */ public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; } /** * 從消息池中獲取一個message對象返回,避免過多創建對象 * 指定一個handler去處理 * 並指定處理的回調接口 */ public static Message obtain(Handler h, Runnable callback) { Message m = obtain(); m.target = h; m.callback = callback; return m; } /** * Same as {@link #obtain()}, but sets the values for both <em>target</em> and * <em>what</em> members on the Message. * * @param h Value to assign to the <em>target</em> member. * @param what Value to assign to the <em>what</em> member. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what) { Message m = obtain(); m.target = h; m.what = what; return m; } /** * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em> * members. * * @param h The <em>target</em> value to set. * @param what The <em>what</em> value to set. * @param obj The <em>object</em> method to set. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what, Object obj) { Message m = obtain(); m.target = h; m.what = what; m.obj = obj; return m; } /** * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, * <em>arg1</em>, and <em>arg2</em> members. * * @param h The <em>target</em> value to set. * @param what The <em>what</em> value to set. * @param arg1 The <em>arg1</em> value to set. * @param arg2 The <em>arg2</em> value to set. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what, int arg1, int arg2) { Message m = obtain(); m.target = h; m.what = what; m.arg1 = arg1; m.arg2 = arg2; return m; } /** * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members. * * @param h The <em>target</em> value to set. * @param what The <em>what</em> value to set. * @param arg1 The <em>arg1</em> value to set. * @param arg2 The <em>arg2</em> value to set. * @param obj The <em>obj</em> value to set. * @return A Message object from the global pool. */ public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj) { Message m = obtain(); m.target = h; m.what = what; m.arg1 = arg1; m.arg2 = arg2; m.obj = obj; return m; } /** * @hide */ public static void updateCheckRecycle(int targetSdkVersion) { if (targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) { gCheckRecycle = false; } } /** * 回收message,先檢查當前消息是否正在使用,如果正在使用拋出異常 * 如果沒有使用就會回收掉,回收之後將不能再使用這個消息 */ public void recycle() { if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it " + "is still in use."); } return; } recycleUnchecked(); } /** * 內部調用回收message,不會檢查當前消息是否正在使用,直接回收,回收之後將不能再使用這個消息 */ void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = -1; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } /** * 複製o的數據(不包括隊列相關的數據)給當前消息 */ public void copyFrom(Message o) { this.flags = o.flags & ~FLAGS_TO_CLEAR_ON_COPY_FROM; this.what = o.what; this.arg1 = o.arg1; this.arg2 = o.arg2; this.obj = o.obj; this.replyTo = o.replyTo; this.sendingUid = o.sendingUid; if (o.data != null) { this.data = (Bundle) o.data.clone(); } else { this.data = null; } } /** * 返回消息的處理時間 */ public long getWhen() { return when; } /* *指定處理該消息的handler */ public void setTarget(Handler target) { this.target = target; } /** * 獲取將處理該消息的handler */ public Handler getTarget() { return target; } /** * 處理消息的回調,如果沒有設置這個回調,調用handler的handleMessage方法進行處理 */ public Runnable getCallback() { return callback; } /** * 獲取Bundle類型的data數據,這個數據是通過setData方法傳遞進來的 * 其實這個方法中的數據可用於進程間數據傳遞,這兒我們不深究 * * @see #peekData() * @see #setData(Bundle) */ public Bundle getData() { if (data == null) { data = new Bundle(); } return data; } /** * 跟setData差不多,但是不同的是返回的data可能爲null */ public Bundle peekData() { return data; } /** * 給data賦值 */ public void setData(Bundle data) { this.data = data; } /** * 發送一個消息給處理該消息的handler,如果這個handler爲null,將會拋出空指針異常 */ public void sendToTarget() { target.sendMessage(this); } /** * 如果返回true,該消息就是異步的,將不會手looper的限制。 * 一般來說我們的消息是受looper的控制是同步的 */ public boolean isAsynchronous() { return (flags & FLAG_ASYNCHRONOUS) != 0; } /** * 對消息的異步進行設置,如果設置爲true,消息不會受looper限制,將會是異步的 */ public void setAsynchronous(boolean async) { if (async) { flags |= FLAG_ASYNCHRONOUS; } else { flags &= ~FLAG_ASYNCHRONOUS; } } /** * 當前消息是否正在使用 */ boolean isInUse() { return ((flags & FLAG_IN_USE) == FLAG_IN_USE); } /*package*/ void markInUse() { flags |= FLAG_IN_USE; } /** * 構造器,一般來說不要直接通過構造器創建message,儘量用obtain方法 */ public Message() { }
- MessageQueue源代碼分析:
* 內部維護消息隊列,這個消息隊列中的消息是按照處理的時間先後順序排隊的 * 跟looper協作進行消息的分發,指派。 * 消息是通過Handler關聯上Looper之後,放到消息隊列中,然 * 後通過looper取出調用handler的dispatchMessage方法進行處理 */ public final class MessageQueue { private static final String TAG = "MessageQueue"; private static final boolean DEBUG = false; // 代表當前消息隊列能否exit private final boolean mQuitAllowed; @SuppressWarnings("unused") private long mPtr; // used by native code Message mMessages; private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>(); private SparseArray<FileDescriptorRecord> mFileDescriptorRecords; private IdleHandler[] mPendingIdleHandlers; // private boolean enqueueMessage; // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout. private boolean mBlocked; // The next barrier token. // Barriers are indicated by messages with a null target whose arg1 field carries the token. private int mNextBarrierToken; private native static long nativeInit(); private native static void nativeDestroy(long ptr); private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/ private native static void nativeWake(long ptr); private native static boolean nativeIsPolling(long ptr); private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events); //構造方法,初始化 MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); } @Override protected void finalize() throws Throwable { try { dispose(); } finally { super.finalize(); } } // Disposes of the underlying message queue. // Must only be called on the looper thread or the finalizer. private void dispose() { if (mPtr != 0) { nativeDestroy(mPtr); mPtr = 0; } } /** * 判斷跟這個消息隊列關聯的looper是不是爲空閒狀態,true表示空閒,false表示非空閒 */ public boolean isIdle() { synchronized (this) { //獲取系統時間 final long now = SystemClock.uptimeMillis(); //如果消息隊列中沒有消息,或者需要處理的消息裏面時間最早的一個都是在當前系統時間的後面,那就代表着空閒 return mMessages == null || now < mMessages.when; } } public void addIdleHandler(@NonNull IdleHandler handler) { if (handler == null) { throw new NullPointerException("Can't add a null IdleHandler"); } synchronized (this) { mIdleHandlers.add(handler); } } public void removeIdleHandler(@NonNull IdleHandler handler) { synchronized (this) { mIdleHandlers.remove(handler); } } public boolean isPolling() { synchronized (this) { return isPollingLocked(); } } private boolean isPollingLocked() { // If the loop is quitting then it must not be idling. // We can assume mPtr != 0 when mQuitting is false. return !mQuitting && nativeIsPolling(mPtr); } public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd, @OnFileDescriptorEventListener.Events int events, @NonNull OnFileDescriptorEventListener listener) { if (fd == null) { throw new IllegalArgumentException("fd must not be null"); } if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } synchronized (this) { updateOnFileDescriptorEventListenerLocked(fd, events, listener); } } public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) { if (fd == null) { throw new IllegalArgumentException("fd must not be null"); } synchronized (this) { updateOnFileDescriptorEventListenerLocked(fd, 0, null); } } private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events, OnFileDescriptorEventListener listener) { final int fdNum = fd.getInt$(); int index = -1; FileDescriptorRecord record = null; if (mFileDescriptorRecords != null) { index = mFileDescriptorRecords.indexOfKey(fdNum); if (index >= 0) { record = mFileDescriptorRecords.valueAt(index); if (record != null && record.mEvents == events) { return; } } } if (events != 0) { events |= OnFileDescriptorEventListener.EVENT_ERROR; if (record == null) { if (mFileDescriptorRecords == null) { mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>(); } record = new FileDescriptorRecord(fd, events, listener); mFileDescriptorRecords.put(fdNum, record); } else { record.mListener = listener; record.mEvents = events; record.mSeq += 1; } nativeSetFileDescriptorEvents(mPtr, fdNum, events); } else if (record != null) { record.mEvents = 0; mFileDescriptorRecords.removeAt(index); } } // Called from native code. private int dispatchEvents(int fd, int events) { // Get the file descriptor record and any state that might change. final FileDescriptorRecord record; final int oldWatchedEvents; final OnFileDescriptorEventListener listener; final int seq; synchronized (this) { record = mFileDescriptorRecords.get(fd); if (record == null) { return 0; // spurious, no listener registered } oldWatchedEvents = record.mEvents; events &= oldWatchedEvents; // filter events based on current watched set if (events == 0) { return oldWatchedEvents; // spurious, watched events changed } listener = record.mListener; seq = record.mSeq; } // Invoke the listener outside of the lock. int newWatchedEvents = listener.onFileDescriptorEvents( record.mDescriptor, events); if (newWatchedEvents != 0) { newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR; } // Update the file descriptor record if the listener changed the set of // events to watch and the listener itself hasn't been updated since. if (newWatchedEvents != oldWatchedEvents) { synchronized (this) { int index = mFileDescriptorRecords.indexOfKey(fd); if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record && record.mSeq == seq) { record.mEvents = newWatchedEvents; if (newWatchedEvents == 0) { mFileDescriptorRecords.removeAt(index); } } } } // Return the new set of events to watch for native code to take care of. return newWatchedEvents; } /** * 如果消息隊列中還有下一個消息,取出這個消息 * * @return */ Message next() { // Return here if the message loop has already quit and been disposed. // This can happen if the application tries to restart a looper after quit // which is not supported. final long ptr = mPtr; if (ptr == 0) { return null; } int pendingIdleHandlerCount = -1; // -1 only during first iteration //下一次循環的時間,相當於一個鬧鐘 int nextPollTimeoutMillis = 0; for (; ; ) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { // 跳過消息隊列中的異步消息 do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // 如果第一個消息的處理時間還沒到,就設定一個鬧鐘,等到鬧鐘響起,再開始處理 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { //獲取一個消息對象 mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { // 消息對立中沒有消息 nextPollTimeoutMillis = -1; } // 所有的消息都處理完之後,退出message if (mQuitting) { dispose(); return null; } // If first time idle, then get the number of idlers to run. // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // Run the idle handlers. // We only ever reach this code block during the first iteration. for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; } } /** * 退出消息隊列,在looper退出的時候調用 * * @param safe true表示安全退出,false強行退出 */ void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { //安全退出 removeAllFutureMessagesLocked(); } else { //強行退出 removeAllMessagesLocked(); } // We can assume mPtr != 0 because mQuitting was previously false. nativeWake(mPtr); } } public int postSyncBarrier() { return postSyncBarrier(SystemClock.uptimeMillis()); } private int postSyncBarrier(long when) { // Enqueue a new sync barrier token. // We don't need to wake the queue because the purpose of a barrier is to stall it. synchronized (this) { final int token = mNextBarrierToken++; final Message msg = Message.obtain(); msg.markInUse(); msg.when = when; msg.arg1 = token; Message prev = null; Message p = mMessages; if (when != 0) { while (p != null && p.when <= when) { prev = p; p = p.next; } } if (prev != null) { // invariant: p == prev.next msg.next = p; prev.next = msg; } else { msg.next = p; mMessages = msg; } return token; } } public void removeSyncBarrier(int token) { // Remove a sync barrier token from the queue. // If the queue is no longer stalled by a barrier then wake it. synchronized (this) { Message prev = null; Message p = mMessages; while (p != null && (p.target != null || p.arg1 != token)) { prev = p; p = p.next; } if (p == null) { throw new IllegalStateException("The specified message queue synchronization " + " barrier token has not been posted or has already been removed."); } final boolean needWake; if (prev != null) { prev.next = p.next; needWake = false; } else { mMessages = p.next; needWake = mMessages == null || mMessages.target != null; } p.recycleUnchecked(); // If the loop is quitting then it is already awake. // We can assume mPtr != 0 when mQuitting is false. if (needWake && !mQuitting) { nativeWake(mPtr); } } } boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { //消息隊列中還沒有消息存在或者當前插入消息的處理時間比隊列中存在 // 的所有消息的處理時間都要早,就將該消息放在隊首 msg.next = p; mMessages = msg; needWake = mBlocked; } else { /** * 將消息存放到隊列的中間位置,根據處理的時機,跟隊列中所有消息的處理時間進行比較,按從早到遲的順序安插 */ 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 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; } /** * 查詢handler相關聯的消息隊列中,是否有指定what和指定obj的消息 * * @param h 想要查詢的關聯handler * @param what 消息的what值 * @param object 消息的obj值 * @return */ boolean hasMessages(Handler h, int what, Object object) { if (h == null) { return false; } synchronized (this) { Message p = mMessages; while (p != null) { if (p.target == h && p.what == what && (object == null || p.obj == object)) { return true; } p = p.next; } return false; } } /** * 查詢handler相關聯的消息隊列中,是否有指定obj的任務 * * @param h 想要查詢的關聯handler * @param object 任務的obj值 * @return */ boolean hasMessages(Handler h, Runnable r, Object object) { if (h == null) { return false; } synchronized (this) { Message p = mMessages; while (p != null) { if (p.target == h && p.callback == r && (object == null || p.obj == object)) { return true; } p = p.next; } return false; } } /** * 移除跟h相關聯的消息隊列中,指定what值和obj值的消息 * * @param h * @param what * @param object */ void removeMessages(Handler h, int what, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && p.what == what && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && n.what == what && (object == null || n.obj == object)) { Message nn = n.next; n.recycleUnchecked(); p.next = nn; continue; } } p = n; } } } /** * 移除跟h相關聯的消息隊列中,指定obj值的任務 * * @param h * @param r * @param object */ void removeMessages(Handler h, Runnable r, Object object) { if (h == null || r == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && p.callback == r && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && n.callback == r && (object == null || n.obj == object)) { Message nn = n.next; n.recycleUnchecked(); p.next = nn; continue; } } p = n; } } } /** * 移除跟指定handler相關聯的消息隊列中,指定obj值的所有消息 * * @param h * @param object */ void removeCallbacksAndMessages(Handler h, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; // Remove all messages at front. while (p != null && p.target == h && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && (object == null || n.obj == object)) { Message nn = n.next; n.recycleUnchecked(); p.next = nn; continue; } } p = n; } } } //回收消息隊列中所有的消息 private void removeAllMessagesLocked() { Message p = mMessages; while (p != null) { Message n = p.next; p.recycleUnchecked(); p = n; } mMessages = null; } /** * 安全退出消息隊列 */ private void removeAllFutureMessagesLocked() { final long now = SystemClock.uptimeMillis(); Message p = mMessages; if (p != null) { if (p.when > now) { //如果在消息設定的處理時間還沒到,直接回收掉,將不會處理 removeAllMessagesLocked(); } else { Message n; for (; ; ) { n = p.next; if (n == null) { return; } if (n.when > now) { break; } p = n; } p.next = null; do { p = n; n = p.next; p.recycleUnchecked(); } while (n != null); } } } void dump(Printer pw, String prefix) { synchronized (this) { long now = SystemClock.uptimeMillis(); int n = 0; for (Message msg = mMessages; msg != null; msg = msg.next) { pw.println(prefix + "Message " + n + ": " + msg.toString(now)); n++; } pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked() + ", quitting=" + mQuitting + ")"); } } ...... }
- Looper源代碼分析:
public final class Looper { private static final String TAG = "Looper"; /* ThreadLocal保存了線程所有的變量,可以通過get方法去獲取對應的變量,取得的變量是什麼取決於泛型, 這兒傳的是Looper,所以獲取的是線程的Looper變量,在prepare方法中會創建一個looper存在sThreadLocal中, 如果沒有先prepare,sThreadLocal.get取得的就是null*/ static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; private Printer mLogging; private long mTraceTag; /** * 初始化一個looper給當前線程 */ public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { //先查詢sThreadLocal,如果已經存在looper會拋出異常 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //創建一個looper對象存放到sThreadLocal中 sThreadLocal.set(new Looper(quitAllowed)); } /** * 爲UI線程準備的,系統初始化UI線程的時候調用。我們一般不需要調用這個方法 */ public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } } /** * 獲取UI線程中的looper變量 */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } } /** * 從MessageQueue中取出Message,調用Handler中的dispatchMessage,對消息進行處理 */ public static void loop() { //獲取到looper,如果沒有之前prepare,取到的會是null,拋出異常 final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } //取出消息中的消息隊裏MessageQueue 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. /** * 確認當前線程的身份是屬於當前本地進程,確保track是屬於這個線程 */ 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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { //開始記錄trace,在ANR分析中會用到trace.txt文件 Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { //調用handler的方法處理消息 msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { //結束trace記錄 Trace.traceEnd(traceTag); } } 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.recycleUnchecked(); } } /** * R獲取當前線程的looper變量 */ public static @Nullable Looper myLooper() { return sThreadLocal.get(); } /** * Return the {@link MessageQueue} object associated with the current * thread. This must be called from a thread running a Looper, or a * NullPointerException will be thrown. */ public static @NonNull MessageQueue myQueue() { return myLooper().mQueue; } /** * 構造方法私有化,在prepare中調用,初始化。 * * @param quitAllowed */ private Looper(boolean quitAllowed) { //創建一個消息隊列,用於存放消息 mQueue = new MessageQueue(quitAllowed); //取得當前線程,讓該looper跟當前線程關聯 mThread = Thread.currentThread(); } /** * 判斷looper是否爲當前線程的looper */ public boolean isCurrentThread() { return Thread.currentThread() == mThread; } /** * 記錄被該looper對象處理的所有消息的控制標誌,如果enabled, * 將會通過Trace.traceBegin和Trace.traceEnd(traceTag)控制記錄每一條消息的處理狀況; * * @param printer A Printer object that will receive log messages, or * null to disable message logging. */ public void setMessageLogging(@Nullable Printer printer) { mLogging = printer; } /** * {@hide} */ public void setTraceTag(long traceTag) { mTraceTag = traceTag; } /** * 退出當前looper操作 * 在當前looper的消息隊列沒有消息需要處理的時候纔可以調用該方法, * 該方法調用的時候會將所有消息隊列中的消息回收, * 在這個方法之後所有的消息將不會再被處理,包括當前正在處理的消息 * 一般來說用quitSafely代替該方法,因爲該方法不安全,他不能保證已經被delivered的消息處理完成 */ public void quit() { mQueue.quit(false); } /** * 安全終止looper * 會先將消息的處理時間在當前時間點之前的消息全部處理完之後纔會終止looper, * 但是不能保證執行時間是在當前時間之後的消息被處理 */ public void quitSafely() { mQueue.quit(true); } /** * 獲取當前looper關聯的線程 */ public @NonNull Thread getThread() { return mThread; } /** * 獲取當前looper持有的消息隊列 */ public @NonNull MessageQueue getQueue() { return mQueue; } public void dump(@NonNull Printer pw, @NonNull String prefix) { pw.println(prefix + toString()); mQueue.dump(pw, prefix + " "); } @Override public String toString() { return "Looper (" + mThread.getName() + ", tid " + mThread.getId() + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}"; } }
- Handler源碼分析:
- 知識點串聯,細節分析
上面將主要的三個類Handler,Message,MessageQueue的源代碼進行了初步的分析,現在我們將幾個重要的方法取出來,具體的分析。將整個機制是怎麼運轉起來的弄明白!
- Looper和MessageQueue,Thread的關係
我們從Handler入手,先看看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,UI線程系統自動調用prepareMainLooper方法,創建了UI線程的looper //如果Handler在子線程中創建,必須先調用prepare創建一個looper,否則myLooper返回的是null,會拋出異常 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; } /** * 構造方法,初始化。跟2個參數的構造方法的區別是,這兒直接給定了looper */ public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
當我們創建Handler的時候,最終調用的都是這兩個構造方法的其中之一。一般情況下,我們是調用到了第一個構造方法。可以看到,在這兩個構造方法中對Handler的四個變量mLooper,mQueue,mCallback,mAsynchronous進行初始化,我們對兩個特殊的變量mLooper和mQueue進行分析,mLooper是通過Looper.myLooper獲取的,mQueue也是通過looper獲取的。我們先具體的分析幾個方法,然後來捋一捋這裏面的關係。
先看一段代碼Looper的構造方法
/** * 構造方法私有化,在prepare中調用,初始化。 * * @param quitAllowed */ private Looper(boolean quitAllowed) { //創建一個消息隊列,用於存放消息 mQueue = new MessageQueue(quitAllowed); //取得當前線程,讓該looper跟當前線程關聯 mThread = Thread.currentThread(); }
看上面的這段代碼,這是Looper類的構造方法,這個方法是private修飾的,也就是說不能在其他類中通過new關鍵字來創建一個Looper的實例,需要通過prepare方法進行創建,我們再來看看prepare方法的具體實現。
/** * 初始化一個looper給當前線程 */ public static void prepare() { prepare(true); } private static void prepare(boolean quitAllowed) { //先查詢sThreadLocal,如果已經存在looper會拋出異常 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //創建一個looper對象存放到sThreadLocal中 sThreadLocal.set(new Looper(quitAllowed)); }
注意看上面的代碼,這兒prepare的時候調用了一個內部private修飾的prepare方法,這兒引入了一個變量sThreadLocal。一會兒我們具體說這個變量,先看看
sThreadLocal.set(newLooper(quitAllowed));這句代碼是調用構造方法創建了一個Looper實例,並且交給了ThreadLocal保存。這兒我想要說明白的一個點,那就是Looper的創建過程,是通過prepare方法調用構造方法進行初始化的,在初始化的時候,創建了一個MessageQueue實例mQueue,並且獲取到了當前線程的實例mThread。通過初始化,讓Looper跟當前線程綁定上了,並且還綁定了一個消息隊列
- Handler和Looper,MessageQueue,Thread的關係
現在清楚了Looper跟Thread還有MessageQueue的關係。我們再來看看Handler跟Looper,Thread,MessageQueue的關係。上面Handler的構造方法初始化的代碼中很明顯,通過Looper.myLooper方法得到了Looper的實例。現在來看看myLooper的具體實現。
/** * 獲取當前線程的looper變量 */ public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
myLooper方法中,是通過sThreadLocal這個變量get出來的。ThreadLocal又是什麼鬼東西?別急,我們先來看看ThreadLocal的get方法,然後我再進行講解。
public T get() { //獲取當前線程的實例 Thread t = Thread.currentThread(); //得到Thread中的ThreadLocalMap實例 ThreadLocalMap map = getMap(t); //遍歷Map集合,將Value值返回 if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) //泛型,根據初始化的時候指定的類型返回當前線程的特定變量 return (T)e.value; } //如果集合爲null,先創建一個null值代替返回 return setInitialValue(); }
ThreadLocal用於存放Thread線程的變量,內部維護了一個內部類ThreadLocalMap類似於HashMap,以鍵值對的形式將線程所有的屬性都存起來。所以Looper在創建的時候也會保存在ThreadLocal中。在那個線程中創建,他就屬於那個線程!在Looper的構造方法中有這麼一段代碼sThreadLocal.set(newLooper(quitAllowed));其實這兒就是將新創建出來的Looper實例保存到了當前線程的ThreadLocal中。
好了,搞清楚ThreadLocal了,那myPrepare方法的實現就不難看懂了吧!其實就是獲取當前線程的Looper實例,因爲前面我們說了Looper跟MessageQueue和Thread是關聯起來的。所以Handler就能通過looper實例去操作Thread,和MessageQueue了。
- Handler和Message,MessageQueue的關係
上面Handler,Looper,MessageQueue,Thread之間的關係已經捋清楚了,現在我們再來看看Handler和Message,MessageQueue,Looper之間的關係
再把這兒捋通,整個Handler消息機制的就活絡起來了,就差中間的一些細節了。
我們一般使用Handler,都是創建一個對象,然後通過Handler的sendMessage,或者sendEmptyMessage或者SendMessageDelay等等方法,將消息發送出去,然後通過回調或者HandlerMessage方法對消息進行處理。
我們來看看下面這幾個Handler類中發送消息的方法:
/** * 將消息push到消息隊列的隊尾,輪到處理該消息的時候會回調handleMessage去處理 * 如果push成功返回true,如果這個消息隊列已經exiting,將會push失敗,返回false */ public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } /** * 將一個沒有攜帶數據,只有what值的空消息push到消息隊列中 */ public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } /** * 將一個沒有攜帶數據,只有what值的空消息push到消息隊列中,但是會在特定的時間過後才能被delivered */ public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } /** * 將一個消息放入隊列,在當前時間+delayMillis(比如:一個小時之後處理,現在是12點,那就是12:00+1*60*60*1000) * 時間點之前應該要處理的消息全部處理完了之後,會在當前handler依附的線程中處理該消息。 * 這個消息將被傳到handleMessage方法中 */ public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } /** * 將一個消息放入消息隊列,在uptimeMillis(比如13:00)這個絕對時間點之前應該處理的消息處理完成之後會處理該消息 */ 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); }
可以看到,這幾個發送消息的方法最終都是調用enqueueMessage方法,也就是說最後起作用的還是enqueueMessage方法。直接將enqueueMessage方法的實現代碼拿出來,具體看一看!
/** * 將消息放入隊列中,在uptimeMillis(13:00)處理這個消息 * * @param queue 將消息放入這個消息隊列 * @param msg 想要處理的消息 * @param uptimeMillis 處理的絕對時間點 * @return */ private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { //指定處理該消息的handler爲當前調用的handler msg.target = this; if (mAsynchronous) { //將消息設置爲可異步 msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
很明顯最後是調用了MessageQuenue中的enqueueMessage方法,這兒的MessageQuenue就是通過Looper獲取到的,一定要時刻記住這一點!同樣的將MessageQueue中的enqueueMessage方法的實現拿出來看看。
boolean enqueueMessage(Message msg, long when) { if (msg.target == null) { throw new IllegalArgumentException("Message must have a target."); } if (msg.isInUse()) { throw new IllegalStateException(msg + " This message is already in use."); } synchronized (this) { if (mQuitting) { IllegalStateException e = new IllegalStateException( msg.target + " sending message to a Handler on a dead thread"); Log.w(TAG, e.getMessage(), e); msg.recycle(); return false; } msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; if (p == null || when == 0 || when < p.when) { //消息隊列中還沒有消息存在或者當前插入消息的處理時間比隊列中存在 // 的所有消息的處理時間都要早,就將該消息放在隊首 msg.next = p; mMessages = msg; needWake = mBlocked; } else { /** * 將消息存放到隊列的中間位置,根據處理的時機,跟隊列中所有消息的處理時間進行比較,按從早到遲的順序安插 */ 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 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
上面的代碼分析註釋已經寫的很詳細了,就是將Message放入到消息隊列中的一個操作,很簡單。但是,其中有很多細節的東西,我們來說一說。這兒引入了一個數據結構隊列。其實隊列跟單鏈表差不多,之間有一定的差別。但是,如果對單鏈表掌握的不錯的同學,理解起隊列也不難!之前我有一篇關於單鏈表的博文《數據結構之Java單鏈表反轉》一文中對單鏈表講解得已經很詳細。如果對隊列理解不到位,可以去看看之後再回過頭來看這篇博文。不然會很費勁。在這兒,就不多說了。
回到正題, 整個消息機制,其實就是包含了兩個部分:
- 將消息放入消息隊列中存放起來,等待處理
- 在特定的時機將消息取出進行處理(這個部分包含了消息的回收)
現在Message已經成功存放到MessageQueue中了,第一部分算是完成了,整個機制算是完成一半!接下來就要去搞清楚第二部分的東西,這些消息是什麼時候被處理的呢?又是誰去處理,誰去分發?在這個處理的過程中上面提到的幾個類分別都扮演什麼角色呢?
我們在子線程中使用Handler的過程是先prepare,然後將消息發送出去,最後調用loop方法。這兒調用prepare方法前面已經講解過了,是爲當前線程創建Looper實例,並且初始化。現在我們再來看看loop方法的實現。
/** * 從MessageQueue中取出Message,調用Handler中的dispatchMessage,對消息進行處理 */ public static void loop() { //獲取到looper,如果沒有之前prepare,取到的會是null,拋出異常 final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } //取出消息中的消息隊裏MessageQueue 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. /** * 確認當前線程的身份是屬於當前本地進程,確保track是屬於這個線程 */ 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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { //開始記錄trace,在ANR分析中會用到trace.txt文件 Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { //調用handler的方法處理消息 msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { //結束trace記錄 Trace.traceEnd(traceTag); } } 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.recycleUnchecked(); } }
上面的代碼很簡單,其實就是調用MessageQueue中的next方法取出消息,取到之後調用handler的dispatchMessage方法對消息進行分發。需要注意的是:在取消息的時候有可能會阻塞,在調用dispatchMessage分發之前會記錄trace,分發完成之後會結束Trac記錄,ANR的出現有可能出現在這個地方,我們分析ANR的時候就是通過這兒生成的trace文件進行分析。
下面我們來看看MessageQueue中next方法的具體代碼實現。
/** * 如果消息隊列中還有下一個消息,根據消息處理的時機取出這個消息 * * @return */ Message next() { // Return here if the message loop has already quit and been disposed. // This can happen if the application tries to restart a looper after quit // which is not supported. final long ptr = mPtr; if (ptr == 0) { return null; } int pendingIdleHandlerCount = -1; // -1 only during first iteration //下一次循環的時間,相當於一個鬧鐘 int nextPollTimeoutMillis = 0; for (; ; ) { if (nextPollTimeoutMillis != 0) { //如果執行的時間不是現在,通過Binder消息機制通知系統執行一條延遲的命令 Binder.flushPendingCommands(); } nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; if (msg != null && msg.target == null) { // 跳過消息隊列中的異步消息 do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } if (msg != null) { if (now < msg.when) { // 計算下一次循環的時機,如果消息處理的時間是現在,計算出來的結果就是0,就不會阻塞 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { //獲取一個消息對象 mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); return msg; } } else { // 消息對立中沒有消息,將下一次執行循環的時間定爲-1,進入阻塞狀態 nextPollTimeoutMillis = -1; } // 所有的消息都處理完之後,退出message if (mQuitting) { dispose(); return null; } // If first time idle, then get the number of idlers to run. // Idle handles only run if the queue is empty or if the first message // in the queue (possibly a barrier) is due to be handled in the future. if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; } if (mPendingIdleHandlers == null) { mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } // Run the idle handlers. // We only ever reach this code block during the first iteration. for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } } } // Reset the idle handler count to 0 so we do not run them again. pendingIdleHandlerCount = 0; // While calling an idle handler, a new message could have been delivered // so go back and look again for a pending message without waiting. nextPollTimeoutMillis = 0; } }
上面的代碼很清楚了,取出消息是一個可能阻塞的過程,因爲有可能現在去取的這個消息需要處理的時機是幾分鐘或者幾秒鐘之後,所以這兒會定一個鬧鐘,然後通知系統做一個延時。這兒大體是這個意思,我們就不深究了哈!
然後在看看Handler中dispatchMessage方法的具體實現
/** * 處理系統消息 * Handle system messages here. */ public void dispatchMessage(Message msg) { //如果msg有回調就交給msg處理 if (msg.callback != null) { handleCallback(msg); } else { //msg沒有回調,創建Handler的時候有給回調就交給這個回調處理 if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } //調用自己的handleMessage方法處理,什麼也沒做,交給子類去具體實現,具體操作。平時我們用的匿名內部類的方式就是走了這一步 handleMessage(msg); } }
很明顯,當Handler收到處理消息的信號的時候,會先看Message有沒有callback回調,有就交給他處理,沒有就看看自己有沒有callback回調,同樣的有,就交給callback回調處理,沒有就調用handleMessage方法。在Handler中handleMessage方法什麼也沒做,所以我們平時簡單的做法就是用一個匿名內部類對消息處理。這種方式不推薦,因爲callback的存在就是爲了考慮性能的問題,爲了避免Handler的子類出現。
到這兒,整個Handler消息機制中的相關類,分別充當的角色,還有彼此之間的聯繫就分析完了。
- Looper和MessageQueue,Thread的關係