天天看點

Android應用程式消息處理機制(Looper、Handler)分析(1)

    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-&gt;SetIntField(messageQueueObj, gMessageQueueClassInfo.mPtr,  

             reinterpret_cast&lt;jint&gt;(nativeMessageQueue));  

    這裡傳進來的參數messageQueueObj即為我們前面在Java層建立的消息隊列對象,而gMessageQueueClassInfo.mPtr即表示在Java類MessageQueue中,其成員變量mPtr的偏移量,通過這個偏移量,就可以把這個本地消息隊列對象natvieMessageQueue儲存在Java層建立的消息隊列對象的mPtr成員變量中,這是為了後續我們調用Java層的消息隊列對象的其它成員函數進入到JNI層時,能夠友善地找回它在JNI層所對應的消息隊列對象。

本文轉自 Luoshengyang 51CTO部落格,原文連結:http://blog.51cto.com/shyluo/966586,如需轉載請自行聯系原作者

繼續閱讀