ActivityThread源碼解析之Handler機制

前言

本文分析了Hander幾個重要類以及他們之間的關係。HandlerAndroid SDK來處理異步消息的核心類。
子線程與主線程通過Handler來進行通信。同時在應用的整個生命週期裏也起着至關重要的作用。

源碼分析

ActivityThread中也使用到了Looper循環,那麼看下它裏面是怎麼使用。

先看下ActivityThread的main函數裏面:

public static void main(String[] args) {
    Looper.prepareMainLooper();
	...
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    ...
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
	...
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

首先是調用prepareMainLooper做一些初始化的操作,接下來就是調用Looper.loop()來啓動死循環處理消息。

在看下thread.attach(false)。他的作用就是將ApplicationThread對象與AMS關聯起來,然後通過Handler通知主線程執行對應操作。

這個Handler是ActivityThread裏面定義的,貼上部分代碼:

private class H extends Handler {
    public void handleMessage(Message msg) {
        if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
        switch (msg.what) {
                ...
            case CREATE_SERVICE:
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
                handleCreateService((CreateServiceData)msg.obj);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                break;
            case BIND_SERVICE:
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                handleBindService((BindServiceData)msg.obj);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                break;
            case UNBIND_SERVICE:
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");
                handleUnbindService((BindServiceData)msg.obj);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                break;
        }
    }

常用生命週期正是在這個Hander裏面執行的,可見這個Looper承載着整個應用生命。

OK!大概說明下Handler的處理機制:handler發送MessageMessageQueueLooper不斷的遍歷消息然後通知Handler處理。如下圖所示:

img

0、

1、初始化

Looper的初始化有兩種。prepareMainLooper()和prepare()。在子線程定義Handler的時候需調用prepare()方法,而UI線程已經定義了一個prepareMainLooper所以無需再執行。

先看看prepare()方法:

public static void prepare() {
    prepare(true);
}
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

參數quitAllowed顧名思義就是true的時候允許quit操作。

看下sThreadLocal.set方法,他的作用就是將新建的Looper對象和當前線程綁定起來。

接着看下new Looper構造方法:

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

沒什麼內容,主要就是新建一個MessageQueue存入mQueue。接下來看下MessageQueue構造方法:

MessageQueue(boolean quitAllowed) {
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();
}

也沒什麼主要是將參數quitAllowed賦值給mQuitAllowed

總的來說就是New出一個Looper和當前的線程綁定還有new處一個MessageQueue賦值給mQueue

下面看下prepareMainLooper()方法:

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

其實也就是比prepare()方法多了sMainLooper = myLooper()操作,就是將主線程的Looper賦值給sMainLooper 。還有就是prepare的參數爲false即不允許quit

2、啓動Looper循環處理消息Looper.loop()

public static void loop() {
    final Looper me = myLooper();//標註1
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;//標註2

    for (;;) {
        // might block
        Message msg = queue.next(); //標註3
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
		...
        try {
            msg.target.dispatchMessage(msg);//標註4
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
		...
        msg.recycleUnchecked();//標註5
    }
}

標註1處先取出當前線程綁定的Looper,標註2處取出該Looper的mQueue也就是prepare的時候新建的mQueue

獲得當前線程對應的MessageQueue之後,接下來用了一個死循環操作Message對象。

標註3處是遍歷queue鏈表的元素。

標註4是執行Message元素的dispatchMessage方法,貼上代碼:

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

注意這邊的msg.targetMessage對象綁定的Handler對象,稍後會介紹。這邊的msg.callback爲NULL,那麼就會調用handleMessage(msg)方法也就是調用Handle創建的時候handleMessage實現。

標註5回收該Message元素。

也就是說該死循環內先從MessageQueue取出Message對象,執行dispatchMessage方法,然後回收Message對象。

重點看下queue.next()方法是如何操作的,看下源碼:

Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {//標註1
        return null;
    }
    for (;;) {
		...
        nativePollOnce(ptr, nextPollTimeoutMillis);//標註2

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;//標註7
            ...
            if (msg != null) {
                if (now < msg.when) {//標註3
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;//標註4
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;//標註5
                    }
                    msg.next = null;
                    ...
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {//標註2
                dispose();
                return null;
            }
        }
    }
}

首先是返回null也就是退出Looper的兩個位置:1、標註1處ptr == 0的時候,百度上看到消息隊列被釋放的時候,由於涉及到native後續再看。2、mQuitting標誌爲true,mQuitting只會被以下方法設置:

void quit(boolean safe) {
    if (!mQuitAllowed) {
        throw new IllegalStateException("Main thread not allowed to quit.");
    }

    synchronized (this) {
        if (mQuitting) {
            return;
        }
        mQuitting = true;
        ...
    }
}

首先是mQuitAllowed標誌爲false(也就是prepareMainLooper初始化的時候設置爲false)的時候直接報錯,因爲主線程不允許退出looper循環。因爲主線程一退出循環,整個應用就退出了。接下來就是設置mQuitting爲true,那麼說明quit方法的作用也就是退出Looper。

那quit方法什麼場景會用到呢?

看下ActivityThread的H的handleMessage方法:

case EXIT_APPLICATION:
	if (mInitialApplication != null) {
		mInitialApplication.onTerminate();
	}
    Looper.myLooper().quit();
    break;

當EXIT_APPLICATION標誌的時候便會調用該方法。但是這邊有個疑惑:當的時候會報錯"Main thread not allowed to quit.",不知道是否是這樣子的邏輯。Mark一下。

下面再回到next()方法中的死循環代碼塊:

標註6處Message msg = mMessages,將當前Message的下一個對象存入msg

標註3處當now < msg.when的時候也就是還沒到Message執行時間,計算出nextPollTimeoutMillis時間下次循環的時候繼續等待 。

標註2處nativePollOnce(ptr, nextPollTimeoutMillis),他的作用是等待nextPollTimeoutMillis毫秒的時間。

標註4處mBlocked = false,注意這個標誌。在Handler發送消息會有用到。

標註5處mMessages = msg.next,將當前msg的下一個對象存入mMessages

最後就是返回msg

總的來說就是:如果還沒到執行時間那麼計算等待時間繼續等,如果到了執行時間標誌置爲false然後返回下一個Message對象。

3、Handler發送消息

發送消息通常有兩種方式,貼上代碼:

            Handler mHandler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    //doSomething
                }
            };

            mHandler.obtainMessage().sendToTarget();
            
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    //doSomething
                }
            });

首先是Handler的構造函數,貼上代碼:

public Handler(Callback callback, boolean async) {
    ...
    mLooper = Looper.myLooper();
    mQueue = mLooper.mQueue;
}

Looper.myLooper()就是從當前線程獲取綁定的Looper對象,所以說當在UI線程新建Handler對象的時候不用考慮Looper的問題。接下來就是在該Looper傳給mQueue

首先看下mHandler.obtainMessage().sendToTarget()

public final Message obtainMessage(){
        return Message.obtain(this);
}

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;

    return m;
}

obtain()是從對象池裏面取出一個Message對象避免每次都new對象。然後將mHandler賦值給Message對象的target。

OK!那看下sendToTarget方法:

public void sendToTarget() {
    target.sendMessage(this);//標註1
}

target就是剛纔mHandler,而this就是mHandler.obtainMessage()。然後一直跟下去就到了sendMessageAtTime方法。

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);//標註2
    }

標註1的就到了標註2,參數queue就是mHandler構造的時候由線程對應Looper對象獲取的。enqueueMessage(queue, msg, uptimeMillis)最終是跑到MessageQueue中的enqueueMessage方法,貼上代碼。

boolean enqueueMessage(Message msg, long when) {
    synchronized (this) {
		...
        msg.when = when;
        Message p = mMessages;//標註1
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {//標註2
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {//標註3
           ...
            Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    ...
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

標註1處mMessages就是下一個要執行的Messages對象,將它賦值給p。

標註2處when是當前Message的執行時間而p.when也就是當前MessageQueue裏最早的執行時間。

如果when比最早的執行時間還早的話分爲兩步處理:

第一步就是排到MessageQueue對前面。

第二部是考慮到兩種情況。MessageQueue是否正在處理也就是mBlocked是否爲false。如果爲ture也就是說looper正在阻塞狀態那就要利用nativeWake方法喚醒。

標註3處如果when比最晚的執行時間還早的話就按時間先後插入MessageQueue鏈表中。

OK,下面看下mHandler.post方式發送消息:

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

和其他方法大同小異。主要是差在getPostMessage(r),看下代碼:

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

最終也是將Message對象交給MessageQueue中,那麼就會執行到dispatchMessage方法。最終會跑到handleCallback方法

private static void handleCallback(Message message) {
    message.callback.run();
}

最終調用了Runnable實現。

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