Android應用程式是通過消息來驅動的,系統為每一個應用程式維護一個消息隊例,應用程式的主線程不斷地從這個消息隊例中擷取消息(Looper),然後對這些消息進行處理(Handler),這樣就實作了通過消息來驅動應用程式的執行,本文将詳細分析Android應用程式的消息處理機制。
<a href="http://blog.51cto.com/attachment/201208/224400715.png" target="_blank"></a>
了解Android應用程式的消息處理過程之後,我們就開始分樣它的實作原理了。與Windows應用程式的消息處理過程一樣,Android應用程式的消息處理機制也是由消息循環、消息發送和消息處理這三個部分組成的,接下來,我們就較長的描述這三個過程。
1. 消息循環
在消息處理機制中,消息都是存放在一個消息隊列中去,而應用程式的主線程就是圍繞這個消息隊列進入一個無限循環的,直到應用程式退出。如果隊列中有消息,應用程式的主線程就會把它取出來,并分發給相應的Handler進行處理;如果隊列中沒有消息,應用程式的主線程就會進入空閑等待狀态,等待下一個消息的到來。在Android應用程式中,這個消息循環過程是由Looper類來實作的,它定義在frameworks/base/core/java/android/os/Looper.java檔案中,在分析這個類之前,我們先看一下Android應用程式主線程是如何進入到這個消息循環中去的。
public final class ActivityThread {
......
public static final void main(String[] args) {
......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
thread.detach();
}
}
這個函數做了兩件事情,一是在主線程中建立了一個ActivityThread執行個體,二是通過Looper類使主線程進入消息循環中,這裡我們隻關注後者。
首先看Looper.prepareMainLooper函數的實作,這是一個靜态成員函數,定義在frameworks/base/core/java/android/os/Looper.java檔案中:
public class Looper {
private static final ThreadLocal sThreadLocal = new ThreadLocal();
final MessageQueue mQueue;
/** 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 final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new 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.
* {@link #prepare()}
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
函數prepareMainLooper做的事情其實就是線上程中建立一個Looper對象,這個Looper對象是存放在sThreadLocal成員變量裡面的,成員變量sThreadLocal的類型為ThreadLocal,表示這是一個線程局部變量,即保證每一個調用了prepareMainLooper函數的線程裡面都有一個獨立的Looper對象。線上程是建立Looper對象的工作是由prepare函數來完成的,而在建立Looper對象的時候,會同時建立一個消息隊列MessageQueue,儲存在Looper的成員變量mQueue中,後續消息就是存放在這個隊列中去。消息隊列在Android應用程式消息處理機制中最重要的元件,是以,我們看看它的建立過程,即它的構造函數的實作,實作frameworks/base/core/java/android/os/MessageQueue.java檔案中:
public class MessageQueue {
private int mPtr; // used by native code
private native void nativeInit();
MessageQueue() {
nativeInit();
它的初始化工作都交給JNI方法nativeInit來實作了,這個JNI方法定義在frameworks/base/core/jni/android_os_MessageQueue.cpp檔案中:
static void android_os_MessageQueue_nativeInit(JNIEnv* env, jobject obj) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (! nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return;
android_os_MessageQueue_setNativeMessageQueue(env, obj, nativeMessageQueue);
在JNI中,也相應地建立了一個消息隊列NativeMessageQueue,NativeMessageQueue類也是定義在frameworks/base/core/jni/android_os_MessageQueue.cpp檔案中,它的建立過程如下所示:
NativeMessageQueue::NativeMessageQueue() {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
它主要就是在内部建立了一個Looper對象,注意,這個Looper對象是實作在JNI層的,它與上面Java層中的Looper是不一樣的,不過它們是對應的,下面我們進一步分析消息循環的過程的時候,讀者就會清楚地了解到它們之間的關系。
這個Looper的建立過程也很重要,不過我們暫時放一放,先分析完android_os_MessageQueue_nativeInit函數的執行,它建立了本地消息隊列NativeMessageQueue對象之後,接着調用android_os_MessageQueue_setNativeMessageQueue函數來把這個消息隊列對象儲存在前面我們在Java層中建立的MessageQueue對象的mPtr成員變量裡面:
static void android_os_MessageQueue_setNativeMessageQueue(JNIEnv* env, jobject messageQueueObj,
NativeMessageQueue* nativeMessageQueue) {
env->SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr,
reinterpret_cast<jint>(nativeMessageQueue));
這裡傳進來的參數messageQueueObj即為我們前面在Java層建立的消息隊列對象,而gMessageQueueClassInfo.mPtr即表示在Java類MessageQueue中,其成員變量mPtr的偏移量,通過這個偏移量,就可以把這個本地消息隊列對象natvieMessageQueue儲存在Java層建立的消息隊列對象的mPtr成員變量中,這是為了後續我們調用Java層的消息隊列對象的其它成員函數進入到JNI層時,能夠友善地找回它在JNI層所對應的消息隊列對象。
本文轉自 Luoshengyang 51CTO部落格,原文連結:http://blog.51cto.com/shyluo/966586,如需轉載請自行聯系原作者