??? ? ? ?ActivityThread類的這個mH成員變量是什么時候創建的呢?我們前面在分析應用程序的消息循環時,說到當應用程序進程啟動之后,就會加載ActivityThread類的main函數里面,在這個main函數里面,在通過Looper類進入消息循環之前,會在當前進程中創建一個ActivityThread實例:
public?final?class?ActivityThread?{??????......????????public?static?final?void?main(String[]?args)?{??????????......????????????ActivityThread?thread?=?new?ActivityThread();??????????thread.attach(false);????????????......??????}??} ??在創建這個實例的時候,就會同時創建其成員變量mH了:
public?final?class?ActivityThread?{??????......????????final?H?mH?=?new?H();????????......??} ????前面說過,H類繼承于Handler類,因此,當創建這個H對象時,會調用Handler類的構造函數,這個函數定義在frameworks/base/core/java/android/os/Handler.java文件中:
public?class?Handler?{??????......????????public?Handler()?{??????????......????????????mLooper?=?Looper.myLooper();??????????......????????????mQueue?=?mLooper.mQueue;??????????......??????}??????????final?MessageQueue?mQueue;??????final?Looper?mLooper;??????......??} ?? ?在Hanlder類的構造函數中,主要就是初始成員變量mLooper和mQueue了。這里的myLooper是Looper類的靜態成員函數,通過它來獲得一個Looper對象,這個Looper對象就是前面我們在分析消息循環時,在ActivityThread類的main函數中通過Looper.prepareMainLooper函數創建的。Looper.myLooper函數實現在frameworks/base/core/java/android/os/Looper.java文件中:
public?class?Looper?{??????......????????public?static?final?Looper?myLooper()?{??????????return?(Looper)sThreadLocal.get();??????}????????......??} ???有了這個Looper對象后,就可以通過Looper.mQueue來訪問應用程序的消息隊列了。
?
?? ? ? ?有了這個Handler對象mH后,就可以通過它來往應用程序的消息隊列中加入新的消息了。回到前面的queueOrSendMessage函數中,當它準備好了一個Message對象msg后,就開始調用mH.sendMessage函數來發送消息了,這個函數定義在frameworks/base/core/java/android/os/Handler.java文件中:
public?class?Handler?{??????......????????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)??????{??????????boolean?sent?=?false;??????????MessageQueue?queue?=?mQueue;??????????if?(queue?!=?null)?{??????????????msg.target?=?this;??????????????sent?=?queue.enqueueMessage(msg,?uptimeMillis);??????????}??????????else?{??????????????......??????????}??????????return?sent;??????}????????......??} ??
?
? ?在發送消息時,是可以指定消息的處理時間的,但是通過sendMessage函數發送的消息的處理時間默認就為當前時間,即表示要馬上處理,因此,從sendMessage函數中調用sendMessageDelayed函數,傳入的時間參數為0,表示這個消息不要延時處理,而在sendMessageDelayed函數中,則會先獲得當前時間,然后加上消息要延時處理的時間,即得到這個處理這個消息的絕對時間,然后調用sendMessageAtTime函數來把消息加入到應用程序的消息隊列中去。
?
?? ? ? ?在sendMessageAtTime函數,首先得到應用程序的消息隊列mQueue,這是在Handler對象構造時初始化好的,前面已經分析過了,接著設置這個消息的目標對象target,即這個消息最終是由誰來處理的:
msg.target?=?this;??? ?
? ?這里將它賦值為this,即表示這個消息最終由這個Handler對象來處理,即由ActivityThread對象的mH成員變量來處理。
?
?
?
? ? ? ? 函數最后調用queue.enqueueMessage來把這個消息加入到應用程序的消息隊列中去,這個函數實現在frameworks/base/core/java/android/os/MessageQueue.java文件中:
public?class?MessageQueue?{??????......????????final?boolean?enqueueMessage(Message?msg,?long?when)?{??????????......????????????final?boolean?needWake;??????????synchronized?(this)?{??????????????......????????????????msg.when?=?when;????????????????????????????Message?p?=?mMessages;??????????????if?(p?==?null?||?when?==?0?||?when?<?p.when)?{??????????????????msg.next?=?p;??????????????????mMessages?=?msg;??????????????????needWake?=?mBlocked;???????????????}?else?{??????????????????Message?prev?=?null;??????????????????while?(p?!=?null?&&?p.when?<=?when)?{??????????????????????prev?=?p;??????????????????????p?=?p.next;??????????????????}??????????????????msg.next?=?prev.next;??????????????????prev.next?=?msg;??????????????????needWake?=?false;???????????????}????????????}??????????if?(needWake)?{??????????????nativeWake(mPtr);??????????}??????????return?true;??????}????????......??} ??
? ?把消息加入到消息隊列時,分兩種情況,一種當前消息隊列為空時,這時候應用程序的主線程一般就是處于空閑等待狀態了,這時候就要喚醒它,另一種情況是應用程序的消息隊列不為空,這時候就不需要喚醒應用程序的主線程了,因為這時候它一定是在忙著處于消息隊列中的消息,因此不會處于空閑等待的狀態。
?第一種情況比較簡單,只要把消息放在消息隊列頭就可以了:
msg.next?=?p;??mMessages?=?msg;??needWake?=?mBlocked;???第二種情況相對就比較復雜一些了,前面我們說過,當往消息隊列中發送消息時,是可以指定消息的處理時間的,而消息隊列中的消息,就是按照這個時間從小到大來排序的,因此,當把新的消息加入到消息隊列時,就要根據它的處理時間來找到合適的位置,然后再放進消息隊列中去:
Message?prev?=?null;??while?(p?!=?null?&&?p.when?<=?when)?{??????prev?=?p;??????p?=?p.next;??}??msg.next?=?prev.next;??prev.next?=?msg;??needWake?=?false;???把消息加入到消息隊列去后,如果應用程序的主線程正處于空閑等待狀態,就需要調用natvieWake函數來喚醒它了,這是一個JNI方法,定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:
static?void?android_os_MessageQueue_nativeWake(JNIEnv*?env,?jobject?obj,?jint?ptr)?{??????NativeMessageQueue*?nativeMessageQueue?=?reinterpret_cast<NativeMessageQueue*>(ptr);??????return?nativeMessageQueue->wake();??} ?這個JNI層的NativeMessageQueue對象我們在前面分析消息循環的時候創建好的,保存在Java層的MessageQueue對象的mPtr成員變量中,這里把它取回來之后,就調用它的wake函數來喚醒應用程序的主線程,這個函數也是定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:
void?NativeMessageQueue::wake()?{??????mLooper->wake();??} ??這里它又通過成員變量mLooper的wake函數來執行操作,這里的mLooper成員變量是一個C++層實現的Looper對象,它定義在frameworks/base/libs/utils/Looper.cpp文件中:
void?Looper::wake()?{??????......????????ssize_t?nWrite;??????do?{??????????nWrite?=?write(mWakeWritePipeFd,?"W",?1);??????}?while?(nWrite?==?-1?&&?errno?==?EINTR);????????.......??} ???這個wake函數很簡單,只是通過打開文件描述符mWakeWritePipeFd往管道的寫入一個"W"字符串。其實,往管道寫入什么內容并不重要,往管道寫入內容的目的是為了喚醒應用程序的主線程。前面我們在分析應用程序的消息循環時說到,當應用程序的消息隊列中沒有消息處理時,應用程序的主線程就會進入空閑等待狀態,而這個空閑等待狀態就是通過調用這個Looper類的pollInner函數來進入的,具體就是在pollInner函數中調用epoll_wait函數來等待管道中有內容可讀的。
?
?? ? ? ?這時候既然管道中有內容可讀了,應用程序的主線程就會從這里的Looper類的pollInner函數返回到JNI層的nativePollOnce函數,最后返回到Java層中的MessageQueue.next函數中去,這里它就會發現消息隊列中有新的消息需要處理了,于就會處理這個消息。
?
轉載于:https://blog.51cto.com/shyluo/966601
總結
以上是生活随笔為你收集整理的Android应用程序消息处理机制(Looper、Handler)分析(5)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。