Android訊息機制不完全解析(上) .
Handler和Message是Android開發者常用的兩個API,我一直對於它的內部實現比較好奇,所以用空閒的時間,閱讀了一下他們的原始碼。
相關的Java Class:
- android.os.Message
- android.os.MessageQueue
- android.os.Looper
- android.os.Handler
相關的C++ Class:
- android.NativeMessageQueue
- android.Looper
- android.LooperCallback
- android.SimpleLooperCallback
- android.Message
- android.MessageHandler
首先,讓我們從相對簡單的java實現開始看起:
Message
Message類可以說是最簡單的,主要提供了一些成員,用以儲存訊息資料。
- public int what;//用以表示訊息類別
- public int arg1;//訊息資料
- public int arg2;//訊息資料
- public Object obj;//訊息資料
public int what;//用以表示訊息類別
public int arg1;//訊息資料
public int arg2;//訊息資料
public Object obj;//訊息資料
- /*package*/ long when;//訊息應該被處理的時間
- /*package*/ Bundle data;//訊息資料
- /*package*/ Handler target;//處理這個訊息的handler
- /*package*/ Runnable callback;//回撥函式
- // sometimes we store linked lists of these things
- /*package*/ Message next;//形成連結串列,儲存Message例項
/*package*/ long when;//訊息應該被處理的時間
/*package*/ Bundle data;//訊息資料
/*package*/ Handler target;//處理這個訊息的handler
/*package*/ Runnable callback;//回撥函式
// sometimes we store linked lists of these things
/*package*/ Message next;//形成連結串列,儲存Message例項
值得一提的是,Android提供了一個簡單,但是有用的訊息池,對於Message這種使用頻繁的型別,可以有效的減少記憶體申請和釋放的次數,提高效能。
- 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 final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
- /**
- * Return a new Message instance from the global pool. Allows us to
- * avoid allocating new objects in many cases.
- */
- public static Message obtain() {
- synchronized (sPoolSync) {
- if (sPool != null) {//訊息池不為空,則從訊息池中獲取例項
- Message m = sPool;
- sPool = m.next;
- m.next = null;
- sPoolSize--;
- return m;
- }
- }
- return new Message();
- }
- /**
- * Return a Message instance to the global pool. You MUST NOT touch
- * the Message after calling this function -- it has effectively been
- * freed.
- */
- public void recycle() {
- clearForRecycle();
- synchronized (sPoolSync) {
- if (sPoolSize < MAX_POOL_SIZE) {//訊息池大小未滿,則放入訊息池
- next = sPool;
- sPool = this;
- sPoolSize++;
- }
- }
- }
- /*package*/ void clearForRecycle() {
- flags = 0;
- what = 0;
- arg1 = 0;
- arg2 = 0;
- obj = null;
- replyTo = null;
- when = 0;
- target = null;
- callback = null;
- data = null;
- }
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {//訊息池不為空,則從訊息池中獲取例項
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
/**
* Return a Message instance to the global pool. You MUST NOT touch
* the Message after calling this function -- it has effectively been
* freed.
*/
public void recycle() {
clearForRecycle();
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {//訊息池大小未滿,則放入訊息池
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
/*package*/ void clearForRecycle() {
flags = 0;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
when = 0;
target = null;
callback = null;
data = null;
}
小結:
- Message的核心在於它的資料域,Handler根據這些內容來識別和處理訊息
- 應該使用Message.obtain(或者Handler.obtainMessage)函式獲取message例項
Handler
首先看看建構函式:
- public interface Callback {
- public boolean handleMessage(Message msg);
- }
public interface Callback {
public boolean handleMessage(Message msg);
}
- public Handler() {
- this(null, false);
- }
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; //使用Callback可以攔截Handler處理訊息,之後會在dispatchMessage函式中,大展身手
- mAsynchronous = async;//設定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());
}
}
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; //使用Callback可以攔截Handler處理訊息,之後會在dispatchMessage函式中,大展身手
mAsynchronous = async;//設定handler的訊息為非同步訊息,暫時先無視這個變數
}
Handler的建構函式最主要的就是初始化成員變數:mLooper和mQueue。 這邊需要注意的一個問題是:Looper.myLooper()不能返回null,否則丟擲RuntimeExeception。稍後詳解Looper.myLooper();函式在何種情況下會丟擲異常。
Handler.obtainMessage系列的函式都會呼叫Message類中對應的靜態方法,從訊息池中獲取一個可用的訊息例項。典型實現如下:
- public final Message obtainMessage()
- {
- return Message.obtain(this);
- }
public final Message obtainMessage()
{
return Message.obtain(this);
}
Handler.post系列和send系列函式最終都會呼叫enqueueMessage函式,把message入列,不同之處在於post系列函式會以Runable引數構建一個Message例項。
- private static Message getPostMessage(Runnable r) {
- Message m = Message.obtain();
- m.callback = r;//一會我們會看到callback非空的message和callback為空的mesage在處理時的差異
- return m;
- }
- public final boolean post(Runnable r)
- {
- return sendMessageDelayed(getPostMessage(r), 0);
- }
- 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);
- }
- //最終都會呼叫這個函式,把message入列
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);//Handler的<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">mAsynchronous屬性,決定了msg是否為asynchronous,稍後在MessageQueue.next函式中,可以看到</SPAN><SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">asynchronous對於訊息處理的影響</SPAN><SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">
- AN> }
- return queue.enqueueMessage(msg, uptimeMillis);
- }
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;//一會我們會看到callback非空的message和callback為空的mesage在處理時的差異
return m;
}
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
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);
}
//最終都會呼叫這個函式,把message入列
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);//Handler的<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">mAsynchronous屬性,決定了msg是否為asynchronous,稍後在MessageQueue.next函式中,可以看到</span><span style="FONT-FAMILY: Arial, Helvetica, sans-serif">asynchronous對於訊息處理的影響</span><span style="FONT-FAMILY: Arial, Helvetica, sans-serif">
</span> }
return queue.enqueueMessage(msg, uptimeMillis);
}
除了這些之外,Handler還提供了hasMessage系列和removeMessages系列函式用以管理Handler對應的MessageQueue中的訊息。
接下來主角登場,Handler.dispatchMessage:
- private static void handleCallback(Message message) {
- message.callback.run();
- }
- /**
- * Subclasses must implement this to receive messages.
- */
- public void handleMessage(Message msg) {
- }
- /**
- * Handle system messages here.
- */
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {//message的callback不為null,則執行
- handleCallback(msg);
- } else {
- if (mCallback != null) {//如果Hanlder的mCallback成員不為null,則呼叫
- if (mCallback.handleMessage(msg)) {//如果handleMessage返回值為true,則攔截訊息
- return;
- }
- }
- handleMessage(msg);//處理訊息
- }
- }
private static void handleCallback(Message message) {
message.callback.run();
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//message的callback不為null,則執行
handleCallback(msg);
} else {
if (mCallback != null) {//如果Hanlder的mCallback成員不為null,則呼叫
if (mCallback.handleMessage(msg)) {//如果handleMessage返回值為true,則攔截訊息
return;
}
}
handleMessage(msg);//處理訊息
}
}
註釋應該比較清楚,不多說。 小結:
- Handler類最為核心的函式是enqueueMessage和dispatcherMessage,前者把待處理的訊息放入MessageQueue,而Looper呼叫後者來處理從MessageQueue獲取的訊息。
- callback不為null(通過post系列函式新增到訊息佇列中)的message無法被攔截,而callback為null的函式可以被Handler的mCallback攔截
Looper
同樣從建構函式看起:
好了,Looper的例項是構造出來,但是如何獲取構造出來的例項呢?
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);//每個Looper有一個MessageQueue
- mRun = true;
- mThread = Thread.currentThread();
- }
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//每個Looper有一個MessageQueue
mRun = true;
mThread = Thread.currentThread();
}
- ** 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);//後臺執行緒的looper都允許退出
- }
- private static void prepare(boolean quitAllowed) {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");//每個執行緒只能有一個Looper
- }
- sThreadLocal.set(new Looper(quitAllowed));//把例項儲存到TLS(Thread Local Save),僅有每個執行緒訪問自己的Looper
- }
- /**
- * Initialize the current thread as a looper, marking it as an
- * application's main looper. The main looper for your application
- * is created by the Android environment, so you should never need
- * to call this function yourself. See also: {@link #prepare()}
- */
- public static void prepareMainLooper() {
- prepare(false);//主執行緒的lopper不可以退出
- synchronized (Looper.class) {
- if (sMainLooper != null) {
- throw new IllegalStateException("The main Looper has already been prepared.");
- }
- sMainLooper = myLooper();
- }
- }
** 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);//後臺執行緒的looper都允許退出
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");//每個執行緒只能有一個Looper
}
sThreadLocal.set(new Looper(quitAllowed));//把例項儲存到TLS(Thread Local Save),僅有每個執行緒訪問自己的Looper
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);//主執行緒的lopper不可以退出
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
因為是私有的建構函式,所以理論上來說只能通過prepare和prepareMainLooper兩個函式來例項化Looper,但是google的註釋也說的很清楚:prepareMainLooper()應該由系統呼叫(有興趣的同學可以去看看AtivityThread類的main函式),所以,應用開發者可以使用的只剩下prepare函式。好了,Looper的例項是構造出來,但是如何獲取構造出來的例項呢?
- /** Returns the application's main looper, which lives in the main thread of the application.
- */
- public static Looper getMainLooper() {
- synchronized (Looper.class) {
- return sMainLooper;
- }
- }
- /**
- * Return the Looper object associated with the current thread. Returns
- * null if the calling thread is not associated with a Looper.
- */
- public static Looper myLooper() {
- return sThreadLocal.get();
- }
/** Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
現在,我們應該知道如何防止Handler例項化的時候,丟擲RuntimeException:在守護執行緒中例項化Handler之前,需要先呼叫Looper.perpare函式來構造Looper例項。 然後,重頭戲來了:
- /**
- * Quits the looper.
- *
- * Causes the {@link #loop} method to terminate as soon as possible.
- */
- public void quit() {
- mQueue.quit();
- }
- /**
- * Run the message queue in this thread. Be sure to call
- * {@link #quit()} to end the loop.
- */
- public static void loop() {
- final Looper me = myLooper();
- if (me == null) {//呼叫looper之前,需要先呼叫perpare,否則您懂的...
- 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 獲取一個下一個訊息,如果當前沒有要處理的訊息,則block,之後我們會看到這個API的實現
- if (msg == null) {//呼叫了MessgeQueu的quit函式後,MessageQueue.next會返回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我們可以列印Looper中處理的訊息
- logging.println(">>>>> Dispatching to " + msg.target + " " +
- msg.callback + ": " + msg.what);
- }
- msg.target.dispatchMessage(msg);//呼叫handler處理訊息
- 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();//回收訊息到訊息池
- }
- }
/**
* Quits the looper.
*
* Causes the {@link #loop} method to terminate as soon as possible.
*/
public void quit() {
mQueue.quit();
}
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {//呼叫looper之前,需要先呼叫perpare,否則您懂的...
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 獲取一個下一個訊息,如果當前沒有要處理的訊息,則block,之後我們會看到這個API的實現
if (msg == null) {//呼叫了MessgeQueu的quit函式後,MessageQueue.next會返回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我們可以列印Looper中處理的訊息
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);//呼叫handler處理訊息
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()函式是Looper類的核心函式,主要迴圈進行兩個操作:- 從MessageQueue中獲取一個訊息,當前沒有訊息需要處理時,則block
- 呼叫message的Handler(target)處理訊息
基本上,我們可以把Looper理解為一個死迴圈,Looper開始work以後,執行緒就進入了以訊息為驅動的工作模型。
小結:
- 每個執行緒最多可以有一個Looper。
- 每個Looper有且僅有一個MessageQueue
- 每個Handler關聯一個MessageQueue,由該MessageQueue關聯的Looper執行(呼叫Hanlder.dispatchMessage)
- 每個MessageQueue可以關聯任意多個Handler
- Looper API的呼叫順序:Looper.prepare >> Looper.loop >> Looper.quit
- Looper的核心函式是Looper.loop,一般loop不會返回,直到執行緒退出,所以需要執行緒完成某個work時,請傳送訊息給Message(或者說Handler)
MessageQueue類是唯一包含native函式的類,我們先大致看一下,稍後C++的部分在詳細解釋:
- private native void nativeInit(); //初始化
- private native void nativeDestroy(); //銷燬
- private native void nativePollOnce(int ptr, int timeoutMillis); //等待<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">timeoutMillis指定的時間</SPAN>
- private native void nativeWake(int ptr);//喚醒<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">nativePollOnce的等待</SPAN>
private native void nativeInit(); //初始化
private native void nativeDestroy(); //銷燬
private native void nativePollOnce(int ptr, int timeoutMillis); //等待<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">timeoutMillis指定的時間</span>
private native void nativeWake(int ptr);//喚醒<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">nativePollOnce的等待</span>
- Message mMessages;//資料域mMessages的型別雖然是Message,但是因為Message.next資料域的原因,其實mMessage是連結串列的第一個元素
- MessageQueue(boolean quitAllowed) {
- mQuitAllowed = quitAllowed;
- nativeInit();//初始化nativeMessageQueue
- }
Message mMessages;//資料域mMessages的型別雖然是Message,但是因為Message.next資料域的原因,其實mMessage是連結串列的第一個元素
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
nativeInit();//初始化nativeMessageQueue
}
對應的,在銷燬的時候:- @Override
- protected void finalize() throws Throwable {
- try {
- nativeDestroy();//銷燬nativeMessageQueue
- } finally {
- super.finalize();
- }
- }
@Override
protected void finalize() throws Throwable {
try {
nativeDestroy();//銷燬nativeMessageQueue
} finally {
super.finalize();
}
}
此外,MessageQueue提供了一組函式(e.g. hasMessage, removeMessage)來查詢和移除待處理的訊息,我們在前面的Handler類上看到的對應函式的實現就是呼叫這組函式。
接下來,看看enqueueMessage函式,Handler函式就是呼叫這個函式把message放到MessageQueue中:
- final boolean enqueueMessage(Message msg, long when) {
- if (msg.isInUse()) {//檢查msg是否在使用中,一會我們可以看到MessageQueue.next()在返回前通過Message.makeInUse函式設定msg為使用狀態,而我們之前看到過Looper.loop中通過呼叫呼叫Message.recycle(),把Message重置為未使用的狀態。
- throw new AndroidRuntimeException(msg + " This message is already in use.");
- }
- if (msg.target == null) {//msg必須知道由那個Handler負責處理它
- throw new AndroidRuntimeException("Message must have a target.");
- }
- boolean needWake;
- synchronized (this) {
- if (mQuiting) {//如果已經呼叫MessageQueue.quit,那麼不再接收新的Message
- RuntimeException e = new RuntimeException(
- msg.target + " sending message to a Handler on a dead thread");
- Log.w("MessageQueue", e.getMessage(), e);
- return false;
- }
- msg.when = when;
- Message p = mMessages;
- if (p == null || when == 0 || when < p.when) {//插到列表頭
- // New head, wake up the event queue if blocked.
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked;//當前MessageQueue處於block狀態,所以需要喚醒
- } else {
- // Inserted within the middle of the queue. Usually we don't have to wake
- // up the event queue unless there is a barrier at the head of the queue
- // and the message is the earliest asynchronous message in the queue.
- needWake = mBlocked && p.target == null && msg.isAsynchronous();//當且僅當MessageQueue因為Sync Barrier而block,並且msg為非同步訊息時,喚醒。 關於msg.isAsyncChronous(),請回去看看Handler.enqueueMessage函式和建構函式
- Message prev;
- for (;;) {<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">// 根據when的大小順序,插入到合適的位置</SPAN>
- 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;
- }
- }
- if (needWake) {
- nativeWake(mPtr);//喚醒nativeMessageQueue
- }
- return true;
- }
- final void quit() {
- if (!mQuitAllowed) {//UI執行緒的Looper訊息佇列不可退出
- throw new RuntimeException("Main thread not allowed to quit.");
- }
- synchronized (this) {
- if (mQuiting) {
- return;
- }
- mQuiting = true;
- }
- nativeWake(mPtr);//喚醒nativeMessageQueue
- }
final boolean enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {//檢查msg是否在使用中,一會我們可以看到MessageQueue.next()在返回前通過Message.makeInUse函式設定msg為使用狀態,而我們之前看到過Looper.loop中通過呼叫呼叫Message.recycle(),把Message重置為未使用的狀態。
throw new AndroidRuntimeException(msg + " This message is already in use.");
}
if (msg.target == null) {//msg必須知道由那個Handler負責處理它
throw new AndroidRuntimeException("Message must have a target.");
}
boolean needWake;
synchronized (this) {
if (mQuiting) {//如果已經呼叫MessageQueue.quit,那麼不再接收新的Message
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
}
msg.when = when;
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {//插到列表頭
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;//當前MessageQueue處於block狀態,所以需要喚醒
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();//當且僅當MessageQueue因為Sync Barrier而block,並且msg為非同步訊息時,喚醒。 關於msg.isAsyncChronous(),請回去看看Handler.enqueueMessage函式和建構函式
Message prev;
for (;;) {<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">// 根據when的大小順序,插入到合適的位置</span>
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;
}
}
if (needWake) {
nativeWake(mPtr);//喚醒nativeMessageQueue
}
return true;
}
final void quit() {
if (!mQuitAllowed) {//UI執行緒的Looper訊息佇列不可退出
throw new RuntimeException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuiting) {
return;
}
mQuiting = true;
}
nativeWake(mPtr);//喚醒nativeMessageQueue
}
關於sync barrier,再補充點解釋: sync barrier是起到了一個阻塞器的作用,它可以阻塞when>它(即執行時間比它晚)的同步訊息的執行,但不影響非同步訊息。sync barrier的特徵是targe為null,所以它只能被remove,無法被執行。MessageQueue提供了下面兩個函式來控制MessageQueue中的sync barrier(如何覺得sync barrier和非同步訊息難以理解的話,選擇性無視就好,因為它們不妨礙我們理解Android訊息機制的原理):- final int enqueueSyncBarrier(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.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;
- }
- }
- final 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.
- final boolean needWake;
- 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.");
- }
- if (prev != null) {
- prev.next = p.next;
- needWake = false;
- } else {
- mMessages = p.next;
- needWake = mMessages == null || mMessages.target != null;//其實我覺得這邊應該是needWake = mMessages != null && mMessages.target != null
- }
- p.recycle();
- }
- if (needWake) {
- nativeWake(mPtr);//有需要的話,喚醒nativeMessageQueue
- }
- }
final int enqueueSyncBarrier(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.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;
}
}
final 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.
final boolean needWake;
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.");
}
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;//其實我覺得這邊應該是needWake = mMessages != null && mMessages.target != null
}
p.recycle();
}
if (needWake) {
nativeWake(mPtr);//有需要的話,喚醒nativeMessageQueue
}
}
重頭戲又來了:
- final Message next() {
- int pendingIdleHandlerCount = -1; // -1 only during first iteration
- int nextPollTimeoutMillis = 0;
- for (;;) {
- if (nextPollTimeoutMillis != 0) {
- Binder.flushPendingCommands();//不太理解,選擇性無視
- }
- nativePollOnce(mPtr, nextPollTimeoutMillis);//等待nativeMessageQueue返回,最多等待nextPollTimeoutMillis毫秒
- synchronized (this) {
- if (mQuiting) {//如果要退出,則返回null
- return null;
- }
- // 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) {//下一個訊息為sync barrier
- // Stalled by a barrier. Find the next asynchronous message in the queue.
- do {
- prevMsg = msg;
- msg = msg.next;
- } while (msg != null && !msg.isAsynchronous());//因為存在sync barrier,僅有非同步訊息可以執行,所以尋在最近的非同步訊息
- }
- if (msg != null) {
- if (now < msg.when) {
- // Next message is not ready. Set a timeout to wake up when it is ready.
- nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);//訊息還沒到執行的時間,所以我們繼續等待msg.when - now毫秒
- } else {
- // Got a message.
- mBlocked = false;//開始處理訊息了,所以不再是blocked狀態
- if (prevMsg != null) {
- prevMsg.next = msg.next;//從連結串列中間移除message
- } else {
- mMessages = msg.next;//從連結串列頭移除message
- }
- msg.next = null;
- if (false) Log.v("MessageQueue", "Returning message: " + msg);
- msg.markInUse();//標記msg正在使用
- return msg;//返回到Looper.loop函式
- }
- } else {
- // No more messages.
- nextPollTimeoutMillis = -1;//沒有訊息可以處理,所以無限制的等待
- }
- // 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)) {<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">// 目前無訊息可以處理,可以執行IdleHandler</SPAN>
- 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("MessageQueue", "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;//Looper.looper呼叫一次MessageQueue.next(),只允許呼叫一輪IdleHandler
- // 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;//因為執行IdleHandler的過程中,可能有新的訊息到來,所以把等待時間設定為0
- }
- }
final Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();//不太理解,選擇性無視
}
nativePollOnce(mPtr, nextPollTimeoutMillis);//等待nativeMessageQueue返回,最多等待nextPollTimeoutMillis毫秒
synchronized (this) {
if (mQuiting) {//如果要退出,則返回null
return null;
}
// 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) {//下一個訊息為sync barrier
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());//因為存在sync barrier,僅有非同步訊息可以執行,所以尋在最近的非同步訊息
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);//訊息還沒到執行的時間,所以我們繼續等待msg.when - now毫秒
} else {
// Got a message.
mBlocked = false;//開始處理訊息了,所以不再是blocked狀態
if (prevMsg != null) {
prevMsg.next = msg.next;//從連結串列中間移除message
} else {
mMessages = msg.next;//從連結串列頭移除message
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();//標記msg正在使用
return msg;//返回到Looper.loop函式
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;//沒有訊息可以處理,所以無限制的等待
}
// 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)) {<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">// 目前無訊息可以處理,可以執行IdleHandler</span>
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("MessageQueue", "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;//Looper.looper呼叫一次MessageQueue.next(),只允許呼叫一輪IdleHandler
// 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;//因為執行IdleHandler的過程中,可能有新的訊息到來,所以把等待時間設定為0
}
}
為了方便大家理解Message的工作原理,先簡單描述nativeWake,和natePollonce的作用:- nativePollOnce(mPtr, nextPollTimeoutMillis);暫時無視mPtr引數,阻塞等待nextPollTimeoutMillis毫秒的時間返回,與Object.wait(long timeout)相似
- nativeWake(mPtr);暫時無視mPtr引數,喚醒等待的nativePollOnce函式返回的執行緒,從這個角度解釋nativePollOnce函式應該是最多等待nextPollTimeoutMillis毫秒
小結:
- MessageQueue作為一個容器,儲存了所有待執行的訊息。
- MessageQueue中的Message包含三種型別:普通的同步訊息,Sync barrier(target = null),非同步訊息(isAsynchronous() = true)。
- MessageQueue的核心函式為enqueueMessage和next,前者用於向容器內新增Message,而Looper通過後者從MessageQueue中獲取訊息,並實現無訊息情況下的等待。
- MessageQueue把Android訊息機制的Java實現和C++實現聯絡起來。
本來我是想一口氣把java實現和C++實現都寫完的,但是,無奈最近工作和個人事務都比較多,稍後為大家奉上C++實現的解析。
相關文章
- Android訊息機制不完全解析(下) .Android
- Android的Handler訊息機制 解析Android
- Handler訊息處理機制原始碼解析 上原始碼
- Handler訊息機制完全解析Handler解析
- 深度解析VC中的訊息傳遞機制(上)
- Android訊息機制Message訊息池Android
- android訊息機制—HandlerAndroid
- 理解 Android 訊息機制Android
- Android訊息機制HandlerAndroid
- Android 之訊息機制Android
- Android的訊息機制Android
- Android原始碼解析之一 非同步訊息機制Android原始碼非同步
- android之 Android訊息機制Android
- Android訊息傳遞之Handler訊息機制Android
- Android非同步訊息機制Android非同步
- Android訊息機制Handler用法Android
- Android 訊息機制詳解Android
- Android訊息機制(七) RxjavaAndroidRxJava
- Android Handler訊息傳遞機制:圖文解析工作原理Android
- Android訊息機制全面解析(Handler,MessageQueue,Looper,Threadlocal)AndroidOOPthread
- Android全面解析之由淺及深Handler訊息機制Android
- Android訊息機制-ThreadLocal原理解析:資料存取Androidthread
- OC訊息機制,訊息轉發機制
- iOS 訊息轉發機制Demo解析iOS
- [Android進階]Android訊息機制Android
- Android Handler 訊息機制詳述Android
- 深入理解Android訊息機制Android
- Android訊息機制原始碼分析Android原始碼
- 訊息機制
- Android 訊息機制詳解(Android P)Android
- 全面剖析Android訊息機制原始碼Android原始碼
- 深入理解 Android 訊息機制原理Android
- 深入探索Android訊息機制之HandlerAndroid
- 淺析Android中的訊息機制Android
- Android程式間通訊–訊息機制及IPC機制實現薦Android
- iOS訊息機制iOS
- SAP訊息機制
- Android 訊息機制:Handler、MessageQueue 和 LooperAndroidOOP