Android開發 Handler MessageQueue Looper消息循環原理分析

Handler概述

Handler在Android開發中非常重要,最常見的使用場景就是在子線程需要更新UI,用Handler來投遞消息到主線程執行UI更新操作。因爲Android系統的View是非線程安全的,所以需要在主線程更新UI。總的來說Handler就是用來做線程間通信,在不同線程之間傳遞消息。注:這篇文章所講到的Handler是在主線程創建的,主線程在開始的時候已經創建了默認的消息循環。後面的文章會講如何創建自己的消息循環。

消息循環主體結圖例分析

Handler Looper原理圖

Handler Looper原理圖

從圖中可以看出,四種顏色分別代表了四個對象,並且大致描述了幾個對象之間的關係,以及消息的流轉過程,首先Handler通過sendMessage將消息投遞給MessageQueue,Looper通過消息循環(loop)不斷的從MessageQueue中取出消息,然後消息被Handler的dispatchMessage分發到handleMessage方法消費掉。

消息循環中涉及的重要對象

Handler

通過Handler的sendMessage等方法來投遞消息到MessageQueue,通過handleMessage來消費Message。Handler必須要有一個已經prepare好的Looper對象,也就是說必須調用了prepare方法(也包括prepareMainLooper方法),究其根本是初始化一個消息隊列,這一過程將在下文中詳細分析。

Looper

Looper負責從MessageQueue中取出消息,然後通過執行message.target.dispatchMessage()消費掉這個消息,這裏的target就是Handler。

MessageQueue

消息隊列,管理Handler投遞過來的消息。

Message

用來承載數據的消息,最終被Handler消費掉。

UML類圖分析

Handler class diagram

Handler class diagram

通過上面的類圖可以清晰的瞭解各個類之間的關係。然後再來分析一下源碼。

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;
        mAsynchronous = async;
 }

在上面這段代碼中,首先是檢查是否存在潛在的內存泄漏,如果該類是匿名內部類,或者是成員類且沒有static修飾符時那麼打印一個內存泄漏風險警告。這是由於這種類型的class持有外部類的this引用,可能導致外部類無法釋放。接下來就是對成員變量mLooper賦值,在文章開頭就提到過,這篇文章中提到的handler對象時在主線程(UI線程)中創建,而Android主線已經有一個消息隊列了,所以直接將mLooper.mQueue賦給Handler的mQueue。

那麼主線程中的消息隊列是怎麼創建的呢?

看下面的關鍵代碼,UI線程在創建的時候,會調用prepareMainLooper()這個方法,創建一個不退出的消息隊列。所以prepareMainLooper這個方法自己永遠也不要調用,它是系統調用的,如果我們需要用自己的消息隊列呢?那麼就應該調用prepare()方法。

public static void prepare() {
        prepare(true);
}
public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
 }

private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        將looper對象裝入ThreadLocal中,Handler就是從它裏面取出looper對象的
        sThreadLocal.set(new Looper(quitAllowed));
}

private Looper(boolean quitAllowed) {
        //創建消息隊列
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
}

消息怎麼被消費的呢?

整個消息循環系統中的幾個重要部件的創建都已經明白了,那麼消息時怎麼循環起來的,又是如何消費的呢?來看看下面是loop源碼的一部分關鍵代碼。代碼非常簡單易懂,就是從消息隊列中取出消息,然後通過msg.target.dispatchMessage(msg)將消息投遞到Handler。

 public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            msg.target.dispatchMessage(msg);
            msg.recycleUnchecked();
        }
    }

消息傳遞的終點

當消息循環中取出的消息被再次傳遞給Handler的時候,這個消息就走到了生命的盡頭(並不代表對象銷燬,有一個消息池來回收消息),從dispatchMessage方法可以看出,消息最終的歸宿有三個,一是消息自身的callback接口,二是handler的callback接口,最後是handleMessage接口。

 public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
}

總結


通過前面從不同方向對Android的Handler消息循環進行分析,基本結構和原理已經清晰,但是還遠遠不夠,在接下來的文章中,將會對前面提到的潛質內存泄漏做一個詳細的分析。轉載自:vjson.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章