Android应用程序消息处理机制(Looper、Handler)分析(1)
??? ? ? ?Android應用程序是通過消息來驅動的,系統為每一個應用程序維護一個消息隊例,應用程序的主線程不斷地從這個消息隊例中獲取消息(Looper),然后對這些消息進行處理(Handler),這樣就實現了通過消息來驅動應用程序的執行,本文將詳細分析Android應用程序的消息處理機制。
?? ? ? ?前面我們學習Android應用程序中的Activity啟動(Android應用程序啟動過程源代碼分析和Android應用程序內部啟動Activity過程(startActivity)的源代碼分析)、Service啟動(Android系統在新進程中啟動自定義服務過程(startService)的原理分析和Android應用程序綁定服務(bindService)的過程源代碼分析)以及廣播發送(Android應用程序發送廣播(sendBroadcast)的過程分析)時,它們都有一個共同的特點,當ActivityManagerService需要與應用程序進行并互時,如加載Activity和Service、處理廣播待,會通過Binder進程間通信機制來知會應用程序,應用程序接收到這個請求時,它不是馬上就處理這個請求,而是將這個請求封裝成一個消息,然后把這個消息放在應用程序的消息隊列中去,然后再通過消息循環來處理這個消息。這樣做的好處就是消息的發送方只要把消息發送到應用程序的消息隊列中去就行了,它可以馬上返回去處理別的事情,而不需要等待消息的接收方去處理完這個消息才返回,這樣就可以提高系統的并發性。實質上,這就是一種異步處理機制。
?? ? ? ?這樣說可能還是比較籠統,我們以Android應用程序啟動過程源代碼分析一文中所介紹的應用程序啟動過程的一個片斷來具體看看是如何這種消息處理機制的。在這篇文章中,要啟動的應用程序稱為Activity,它的默認Activity是MainActivity,它是由Launcher來負責啟動的,而Launcher又是通過ActivityManagerService來啟動的,當ActivityManagerService為這個即將要啟的應用程序準備好新的進程后,便通過一個Binder進程間通信過程來通知這個新的進程來加載MainActivity,如下圖所示:
?? ?它對應Android應用程序啟動過程中的Step 30到Step 35,有興趣的讀者可以回過頭去參考Android應用程序啟動過程源代碼分析一文。這里的Step 30中的scheduleLaunchActivity是ActivityManagerService通過Binder進程間通信機制發送過來的請求,它請求應用程序中的ActivityThread執行Step 34中的performLaunchActivity操作,即啟動MainActivity的操作。這里我們就可以看到,Step 30的這個請求并沒有等待Step 34這個操作完成就返回了,它只是把這個請求封裝成一個消息,然后通過Step 31中的queueOrSendMessage操作把這個消息放到應用程序的消息隊列中,然后就返回了。應用程序發現消息隊列中有消息時,就會通過Step 32中的handleMessage操作來處理這個消息,即調用Step 33中的handleLaunchActivity來執行實際的加載MainAcitivy類的操作。
?? ? ? ?了解Android應用程序的消息處理過程之后,我們就開始分樣它的實現原理了。與Windows應用程序的消息處理過程一樣,Android應用程序的消息處理機制也是由消息循環、消息發送和消息處理這三個部分組成的,接下來,我們就詳細描述這三個過程。
?? ? ? ?1. 消息循環
?? ? ? ?在消息處理機制中,消息都是存放在一個消息隊列中去,而應用程序的主線程就是圍繞這個消息隊列進入一個無限循環的,直到應用程序退出。如果隊列中有消息,應用程序的主線程就會把它取出來,并分發給相應的Handler進行處理;如果隊列中沒有消息,應用程序的主線程就會進入空閑等待狀態,等待下一個消息的到來。在Android應用程序中,這個消息循環過程是由Looper類來實現的,它定義在frameworks/base/core/java/android/os/Looper.java文件中,在分析這個類之前,我們先看一下Android應用程序主線程是如何進入到這個消息循環中去的。
?? ? ? ?在Android應用程序進程啟動過程的源代碼分析一文中,我們分析了Android應用程序進程的啟動過程,Android應用程序進程在啟動的時候,會在進程中加載ActivityThread類,并且執行這個類的main函數,應用程序的消息循環過程就是在這個main函數里面實現的,我們來看看這個函數的實現,它定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
? ? ? ?這個函數做了兩件事情,一是在主線程中創建了一個ActivityThread實例,二是通過Looper類使主線程進入消息循環中,這里我們只關注后者。
?
?? ? ? ?首先看Looper.prepareMainLooper函數的實現,這是一個靜態成員函數,定義在frameworks/base/core/java/android/os/Looper.java文件中:
? ? ? ? 函數prepareMainLooper做的事情其實就是在線程中創建一個Looper對象,這個Looper對象是存放在sThreadLocal成員變量里面的,成員變量sThreadLocal的類型為ThreadLocal,表示這是一個線程局部變量,即保證每一個調用了prepareMainLooper函數的線程里面都有一個獨立的Looper對象。在線程是創建Looper對象的工作是由prepare函數來完成的,而在創建Looper對象的時候,會同時創建一個消息隊列MessageQueue,保存在Looper的成員變量mQueue中,后續消息就是存放在這個隊列中去。消息隊列在Android應用程序消息處理機制中最重要的組件,因此,我們看看它的創建過程,即它的構造函數的實現,實現frameworks/base/core/java/android/os/MessageQueue.java文件中:
?? ?它的初始化工作都交給JNI方法nativeInit來實現了,這個JNI方法定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中:
?? ?在JNI中,也相應地創建了一個消息隊列NativeMessageQueue,NativeMessageQueue類也是定義在frameworks/base/core/jni/android_os_MessageQueue.cpp文件中,它的創建過程如下所示:
? ?它主要就是在內部創建了一個Looper對象,注意,這個Looper對象是實現在JNI層的,它與上面Java層中的Looper是不一樣的,不過它們是對應的,下面我們進一步分析消息循環的過程的時候,讀者就會清楚地了解到它們之間的關系。
?
?? ? ? ?這個Looper的創建過程也很重要,不過我們暫時放一放,先分析完android_os_MessageQueue_nativeInit函數的執行,它創建了本地消息隊列NativeMessageQueue對象之后,接著調用android_os_MessageQueue_setNativeMessageQueue函數來把這個消息隊列對象保存在前面我們在Java層中創建的MessageQueue對象的mPtr成員變量里面:
?? ?這里傳進來的參數messageQueueObj即為我們前面在Java層創建的消息隊列對象,而gMessageQueueClassInfo.mPtr即表示在Java類MessageQueue中,其成員變量mPtr的偏移量,通過這個偏移量,就可以把這個本地消息隊列對象natvieMessageQueue保存在Java層創建的消息隊列對象的mPtr成員變量中,這是為了后續我們調用Java層的消息隊列對象的其它成員函數進入到JNI層時,能夠方便地找回它在JNI層所對應的消息隊列對象。
轉載于:https://blog.51cto.com/shyluo/966586
總結
以上是生活随笔為你收集整理的Android应用程序消息处理机制(Looper、Handler)分析(1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不同配置决定不同的复制的流程
- 下一篇: CommandArgument传多个值到