1. 程式人生 > >Android非同步訊息處理機制的原始碼分析

Android非同步訊息處理機制的原始碼分析

1、背景

相信做過一段時間的Android開發都瞭解,當我們在子執行緒中更新UI時會丟擲異常,導致程式崩潰,Android4.0之後只允許在UI執行緒中更新介面,但是我們也不能再UI執行緒中處理耗時操作,那樣會導致應用程式無響應(即出現ANR)。
那如果想解決以上問題我們應該如何操作呢?我相信大家肯定都會想到使用Android的非同步機制,沒錯這也是最簡單的一種處理方式。非同步機制的使用我相信大家都已經很熟悉了,那今天我們就從原始碼的角度來分析一下該機制。

2、 示例

首先我們來看一個簡單的Handler應用示例程式碼

public class HandlerTestActivity
extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); } private void initData() { new Thread() { public void run() { // (1)這步很重要
Looper.prepare(); new Handler() { public void handleMessage(Message msg) { // 程式碼邏輯處理 mHandler.sendEmptyMessage(0); }; }; // (2)這步也很重要 Looper.loop(); }; }.start(); } // (3)這裡有一個記憶體洩漏問題
// This Handler class should be static or leaks might occur private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 0: // 接收訊息後的處理 break; default: break; } }; }; protected void onStop() { super.onStop(); mHandler.removeCallbacksAndMessages(null); }; }

以上就是最簡單的Handler在子執行緒中操作UI執行緒,對於Handler的使用大家可以自己去摸索,我們今天的重點在於對Handler的原始碼進行分析。

3、原始碼分析

本次分析的原始碼是基於Android5.1系統,我們首先從Handler的建構函式開始入手吧。

Handler和Looper例項化

Handler有多個過載的構造器,但是都是大同小異的,所以我們就分析一個使用最多的無參構造器。

/**
  * Default constructor associates this handler with the {@link Looper} for the
  * current thread.
  * If this thread does not have a looper, this handler won't be able to receive messages so an exception is thrown.
  */
    public Handler() {
        this(null, false);
    }

這是Handler最常使用的無參構造器,它呼叫了本類另外一個有參構造器。
PS:註釋也很重要,如果當前執行緒沒有looper,這個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());
            }
        }
//(1)這裡獲取一個Looper物件
        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;
    }

我們進入到Handler的另外一個構造器中,程式碼中的(1)處mLooper = Looper.myLooper(),這裡獲取Looper物件,如果獲取的Looper物件為null,將丟擲Can’t create handler inside thread that has not called Looper.prepare()異常。

我們進入到Looper物件的myLooper方法中

/**
  * Return the Looper object associated with the current thread.  Returns
  * null if the calling thread is not associated with a Looper.
  */
    public static Looper myLooper() {
        return sThreadLocal.get();
    }

這裡只是簡單的從sThreadLocal中通過get方法獲取Looper物件,我們來看一下sThreadLocal是什麼?

// sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

它是一個static final型別的ThreadLocal <Looper>物件,所以當sThreadLocal中存在Looper物件時將取出Looper物件,否則將返回null。

既然可以通過sThreadLocal物件取出Looper物件,那一定會有set()方法將Looper存入sThreadLocal物件中,是的接下來我們看一下哪裡有set方法。

還記得之前在子執行緒中呼叫Handler的方法之前需要呼叫Looper.prepare()方法嗎?接下來我們將進入該方法檢視其原始碼。

/** 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 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");
        }
        //(1)我們重點看此處程式碼
        sThreadLocal.set(new Looper(quitAllowed));
    }

由原始碼可見prepare方法直接呼叫的是prepare(boolean)方法,這裡是對prepare方法做了一次封裝,引數quitAllowed直接傳入true(Ps:這個引數很重要,涉及到能否退出訊息佇列),我們看(1)處程式碼sThreadLocal.set(new Looper(quitAllowed)),終於看到了sThreadLocal物件的set方法啦,它設定的是一個Looper物件,進入該方法。

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

可以看到Looper的建構函式中建立了一個MessageQueue物件(Ps:MessageQueue是一個訊息佇列,用於將收到的訊息進行排列,並按序處理),並獲取到當前執行緒,這裡可以看出一個Looper物件只有一個MessageQueue。

這裡就有一個疑問了,那我們平時在UI執行緒中建立Handler時並沒有呼叫Looper.prepare()方法,但在使用的過程中也沒有丟擲異常啊?這是因為在UI執行緒(Activity等)啟動時已經幫我們呼叫了Looper.prepare()方法了,我們來看其原始碼。但在看其原始碼之前我們先說明一下,我們平時一直都認為Activity的入口是OnCreate方法,其實Android應用的上一個入口是ActivityThread類的main方法,這個我們將在後面的部落格中詳述。
我們進入ActivityThread.java類的main方法

public static void main(String[] args) {
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        Security.addProvider(new AndroidKeyStoreProvider());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");
        //(1)此處呼叫了Looper.prepareMainLooper()方法
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        //(2)此處呼叫了Looper.loop()方法
        Looper.loop();
        //(3)此處丟擲一個異常
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

1、我們先看(1)處程式碼,此處呼叫了Looper.prepareMainLooper()方法, 我們進入該方法。

/**
 - 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.  See also: {@link #prepare()}
  */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    /** Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

通過prepareMainLooper方法可以看出,該方法通過呼叫myLooper()方法從而得到一個Looper物件,這個Looper物件一直儲存在sMainLooper變數中,當需要獲取該物件時只需呼叫getMainLooper()方法即可。
2、我們再來看(2)(3)兩處程式碼,(2)處和之前一樣呼叫了loop()方法,而(3)處此時卻丟擲異常,其實在這裡完全不用擔心丟擲異常會有問題,因為(2)這裡是一個死迴圈,正常情況下程式無法到達(3)處,除非程式出現異常,好啦我們對Handler的構造器和Looper.prepare()方法也就分析到這裡了,我們來總結一下。

  • 當我們在主執行緒中可以直接建立Handler,而在子執行緒中需要先呼叫Looper.prepare()後才能建立Handler,否在會丟擲Can’t create handler inside thread that has not called Looper.prepare()的異常。
  • 可通過Looper.myLooper()方法獲取當前執行緒的Looper物件,而通過Looper.getMainLooper()方法獲取主執行緒Looper例項。
  • 每個執行緒只能擁有一個Looper物件,否則會丟擲異常,而一個Looper也只能對應一個MessageQueue。
  • 一個執行緒只能有一個Looper例項,一個MessageQueue例項,可以有多個Handler例項。

到這裡Handler我們也建立好了,也就可以開始分析傳送和處理訊息的原始碼了。

Handler收發訊息機制

Handler有多個過載的傳送訊息的方法,如sendMessage,sendEmptyMessageDelayed,sendEmptyMessage等,但是通過原始碼發現除了sendMessageAtFrontOfQueue方法外,其餘的傳送訊息的方法最終都會通過sendMessageAtTime方法來發送訊息,現在我們來看一下這兩個方法的區別。
咱們先看sendMessageAtTime方法:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        //(1)注意這裡的賦值語句,此處的mQueue是Handler中的變數
        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);
    }

緊接著我們在來看一下sendMessageAtFrontOfQueue方法:

public final boolean sendMessageAtFrontOfQueue(Message msg) {
//(1)注意這裡的賦值語句,此處的mQueue是Handler中的變數
        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, 0);
    }

通過原始碼可以發現,表面上sendMessageAtFrontOfQueue和其他傳送訊息的方法不同,但實質上是相同的,sendMessageAtFrontOfQueue方法其實就是sendMessageAtTime方法的一個特例(即傳入的uptimeMillis=0,也就是可以通過這個方法將message放入Queue的最前面),同時注意(1)處程式碼,將Handler的變數mQueue賦值給區域性變數queue。

那這樣我們就可以直接分析sendMessageAtTime方法,可以看到其最終呼叫了enqueueMessage這個方法,我們進入該方法:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //(1)注意此處的程式碼邏輯,將Handler本身賦值給msg.target變數(重要)
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

發現該方法有三個引數:

  • queue引數:是上一個方法的sendMessageAtTime傳遞而來的,而最終Handler的mQueue變數是在哪裡賦值的呢?其實之前我們分析過,在Handler的構造器中有mQueue = mLooper.mQueue,此時將Looper的變數mQueue賦值過來,而Looper的mQueue變數是在Looper的構造器中創建出來的
  • msg引數:即我們需要傳送的訊息
  • uptimeMillis引數:表示傳送訊息的時間

同時請注意(1)處程式碼邏輯,將需要傳送的訊息msg的target屬性賦值為Handler物件(也就是進行繫結),緊接著呼叫了queue物件的enqueueMessage方法,我們進入該方法。

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                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;
    }

通過這段程式碼發現Handler傳送訊息的實質就是將Message加入到MessageQueue的過程,另可以看出訊息插入佇列的實質就是將所有的訊息按時間進行排序(uptimeMillis引數)。

到這裡Handler如何傳送訊息以及將訊息如何存入佇列就分析結束了,那既然訊息都已經存入隊列了,現在我們也該學習如何從佇列中取出訊息了。還記得之前的示例中我們在子執行緒中呼叫了Looper.loop()方法嗎?其實該方法就是從佇列中取出訊息,我們來看其原始碼。

/**
  * Run the message queue in this thread. Be sure to call
  * {@link #quit()} to end the loop.
  */
    public static void loop() {
        //(1)通過Looper的myLooper靜態方法獲得Looper物件
        final Looper me = myLooper();
        //如果在呼叫loop方法之前沒有呼叫prepare方法將會丟擲異常
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //(2)此處通過Looper物件mQueue屬性獲得訊息佇列
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        //(3)此處為死迴圈,然後通過MessageQueue的next方法不斷的獲取訊息
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            //(4)此處呼叫msg.target物件的dispatchMessage()方法
            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }

我們來分析上面原始碼中的(1)-(4)處邏輯。
(1):此處通過Looper的myLooper方法獲得Looper物件
(2):此處通過Looper物件mQueue屬性獲得訊息佇列
(3):此處通過死迴圈不斷的獲得訊息佇列的中的訊息,當訊息佇列中沒有訊息時,該方法將會進入阻塞狀態,並一直等待新訊息
(4):此處呼叫msg.target物件的dispatchMessage()方法,還記得之前我們將什麼物件賦值給msg.target屬性嗎?在Handler的enqueueMessage方法中,我們將msg.target = this即Handler物件賦值給msg.target屬性,所以此處自然的回調了Handler的dispatchMessage()方法。

接下來我們的重點將進入Handler的dispatchMessage方法。

/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        //(1)這裡是第一種處理方式
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            //(2)這裡是第二種處理方式
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //(3)這裡是第三種處理方式
            handleMessage(msg);
        }
    }

在dispatchMessage方法中有三種方式處理msg訊息,我們分別看一下這三種方式處理的函式。

//(1)
    private static void handleCallback(Message message) {
        message.callback.run();
    }
//(2)
/**
  * Callback interface you can use when instantiating a Handler to avoid
  * having to implement your own subclass of Handler.
  *
  * @param msg A {@link android.os.Message Message} object
  * @return True if no further handling is desired
  */
     public interface Callback {
        public boolean handleMessage(Message msg);
    }
//(3)
/**
  * Subclasses must implement this to receive messages.
  */
     public void handleMessage(Message msg) {
    }

以上分別為dispatchMessage中對應的三種處理方式,我們來分別分析下哪種情況下會分別使用:
(1):當在呼叫Handler的post方式時,會傳入一個Runnable物件,此刻會呼叫第一種方式的run方法,如:

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

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

(2)當在建立Handler例項時,呼叫以下型別的Handler構造器,即傳入一個Callback回撥介面,如:

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

此時在呼叫dispatchMessage方法時就會選擇第二種處理方式。
(3)第三種處理方式相信大家都比較熟悉了,這裡也就不做過多的解釋了。

接下來我們分析另外一個問題,之前不是說MessageQueue在獲取訊息的時候是一個死迴圈嘛,那這裡應該如果結束掉這個死迴圈呢?當然Android肯定為我們提供了這樣的方法,這裡Looper有一個quit()方法,我們先看其原始碼:

    public void quit() {
        //呼叫是MessageQueue的quit方法
        mQueue.quit(false);
    }

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

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            //(2)mQuitting變數
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }

1、上面(1)處程式碼看到沒,通過判斷標記mQuitAllowed來決定該訊息佇列是否可以退出,然而當mQuitAllowed為fasle時丟擲的異常竟然是”Main thread not allowed to quit.“。
還記得這個mQuitAllowed引數從什麼地方賦值的,就是在呼叫Looper.prepare方式時,系統預設將其賦值為true(即prepare(true)),當在主執行緒中呼叫quit方法時將會丟擲異常,原因是prepareMainLooper方法中賦的值是false(即prepare(false))。
2、繼續往下看程式碼,可以發現quit的實質就是對mQuitting變數置位,這個mQuitting變數在MessageQueue的阻塞等待next方法中用做了判斷條件,所以可以通過quit方法退出整個當前執行緒的loop迴圈。

到此Android的非同步訊息處理機制就分析的差不多了,接下來我們做一些總結。

4、總結和拓展

通過上面的原始碼分析我們用幾張圖來展示Handler,Message,Looper,MessageQueue直接的關係(圖片來源於網路)。
圖片來源於網路

接下來我們來看幾個平時的常見問題:
1、Activity的runOnUiThread(Runnable action)方法

/**
  * Runs the specified action on the UI thread. If the current thread is the UI
  * thread, then the action is executed immediately. If the current thread is
  * not the UI thread, the action is posted to the event queue of the UI thread.
  * @param action the action to run on the UI thread
  */
    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

可以看出最終還是呼叫了Handler的post方法。

2、View的post(Runnable action)和postDelayed(Runnable action, long delayMillis)方法

    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }
        // Assume that post will succeed later
        ViewRootImpl.getRunQueue().post(action);
        return true;
    }

最終呼叫還是Handler的post方法。

3、Handler傳送訊息時最好通過obtainMessage()方法,而不是new Message,Handler的obtainMessage有多個過載的方法如obtainMessage(int what)、obtainMessage(int what, Object obj)等,因為這個方法中包含一個Message池,可以避免過多的分配記憶體。

4、在文章剛開始的示例中,我們在示例中標註的(3)部分有提及到建立Handler例項時可能會產生記憶體洩漏問題,這裡的記憶體洩漏是由於Handler存在其所在Activity的引用,導致Activity無法被及時的回收。那這裡應該如何操作呢?有兩種方式:
(1)在Handler使用結束後,使用removeMessages或removeCallbacksAndMessages將對應的Message移除。
(2)將內部類Handler宣告為靜態類,靜態類不持有外部類的物件,所以Activity可以被回收。

5、HandlerThread原始碼分析

很多人肯定會經常看到HandlerThread這個類,但是也不清楚和Handler到底有什麼關係,所以今天我們就來分析一下該類原始碼,如下:

/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 */
public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    //可重寫該方法,在Looper.loop之前處理一些邏輯問題
    protected void onLooperPrepared() {
    }
    //HandlerThread執行緒的run方法
    @Override
    public void run() {
        mTid = Process.myTid();
        //建立Looper物件和MessageQueue物件,需要線上程的start方法後執行
        Looper.prepare();
        synchronized (this) {
            //獲取Looper物件,喚起所有執行緒
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        //開始迴圈取訊息
        Looper.loop();
        mTid = -1;
    }

    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason is isAlive() returns false, this method will return null. If this thread 
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    /**
     * Quits the handler thread's looper.
     * <p>
     * Causes the handler thread's looper to terminate without processing any
     * more messages in the message queue.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p class="note">
     * Using this method may be unsafe because some messages may not be delivered
     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
     * that all pending work is completed in an orderly manner.
     * </p>
     *
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     *
     * @see #quitSafely
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            //退出訊息佇列
            looper.quit();
            return true;
        }
        return false;
    }

    /**
     * Quits the handler thread's looper safely.
     * <p>
     * Causes the handler thread's looper to terminate as soon as all remaining messages
     * in the message queue that are already due to be delivered have been handled.
     * Pending delayed messages with due times in the future will not be delivered.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p>
     * If the thread has not been started or has finished (that is if
     * {@link #getLooper} returns null), then false is returned.
     * Otherwise the looper is asked to quit and true is returned.
     * </p>
     *
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    /**
     * Returns the identifier of this thread. See Process.myTid().
     */
    public int getThreadId() {
        return mTid;
    }
}

以上就是HandlerThread的整個原始碼,其實說白了HandlerThread就是Thread、Handler、Looper的組合,將這些統一封裝在HandlerThread中,方便開發者使用。

接下來我們看一個HandlerThread的例項:

public class HandlerThreadActivity extends Activity {
    private HandlerThread mHandlerThread = null;
    private Handler mHandler = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        initData();
    }

    private void initData() {
        mHandlerThread = new HandlerThread("HandlerThread");
        //必須在建立Handler之前呼叫start方法
        mHandlerThread.start();
        //將當前mHandlerThread子執行緒的Looper傳入mHandler
        mHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //子執行緒傳送訊息
            }
        };

        //從主執行緒往子執行緒傳送訊息
        mThreadHandler.sendEmptyMessage(0);
    }
}

好啦,到此整個Android非同步訊息處理機制我們就完全分析結束了,相信大家已經對它很瞭解了,那今天就到這裡啦。

相關推薦

Android非同步訊息處理機制原始碼分析

宣告:本文是參考了以下幾位大神的文章,自己按照自己的思維習慣整理的筆記,並新增一些相關的內容。如有不正確的地方歡迎留言指出,謝謝! 郭霖部落格 鴻洋部落格 任玉剛《Android開發藝術探索》 一. Andoid訊息機制概述

Android非同步訊息處理機制詳解及原始碼分析

PS一句:最終還是選擇CSDN來整理髮表這幾年的知識點,該文章平行遷移到CSDN。因為CSDN也支援MarkDown語法了,牛逼啊! 【工匠若水 http://blog.csdn.net/yanbober 轉載煩請註明出處,尊重分享成果】 最近相對來說比較閒,加上養病,所

Android非同步訊息處理機制原始碼分析

1、背景 相信做過一段時間的Android開發都瞭解,當我們在子執行緒中更新UI時會丟擲異常,導致程式崩潰,Android4.0之後只允許在UI執行緒中更新介面,但是我們也不能再UI執行緒中處理耗時操作,那樣會導致應用程式無響應(即出現ANR)。 那如果想解

android 非同步訊息處理機制 — AHandler

1. 引入 ALooper、AHandler、AMessage 在 android multimedia stagefright 的框架程式碼中,通篇都是這幾個類的身影,所以熟悉 android 多媒體框架的第一步必須理解這幾個類的含義。 這幾個類是為了實現非同步訊息機制而設計的

Android非同步訊息處理機制:Looper、Handler、Message

1 簡介 Handler,Looper,Message這三者都與Android非同步訊息處理執行緒相關, Looper:負責建立一個MessageQueue,然後進入一個無限迴圈體不斷從該MessageQueue中讀取訊息; Handler:訊息建立者,一個或者多個

(轉載)Android 非同步訊息處理機制 讓你深入理解 Looper、Handler、Message三者關係

很多人面試肯定都被問到過,請問Android中的Looper , Handler , Message有什麼關係?本篇部落格目的首先為大家從原始碼角度介紹3者關係,然後給出一個容易記憶的結論。 1、 概述 Handler 、 Looper 、Message

深入理解Android非同步訊息處理機制

一。概述   Android 中的非同步訊息處理主要分為四個部分組成,Message、Hndler、MessageQueue 和 Looper。其關係如下圖所示:     1. Message 是執行緒之間傳遞的訊息,它可以在內部攜帶少量資訊,用於在不同執行緒之間交換資料。   2. Messag

android非同步訊息處理機制

 android非同步訊息處理主要由四部分組成:Handler,Looper,Message,MessageQueue​ Message:執行緒之間傳遞的訊息,可以在內部攜帶少量訊息 MessageQueue: Looper:每個執行緒有且最多隻能有一個Looper物件

Android非同步訊息處理機制 handler

我們都知道,Android UI是執行緒不安全的,如果在子執行緒中嘗試進行UI操作,程式就有可能會崩潰。相信大家在日常的工作當中都會經常遇到這個問題,解決的方案應該也是早已爛熟於心,即建立一個Message物件,然後藉助Handler傳送出去,之後在Handler的han

Android 非同步訊息處理機制解析

一、Message、Handler、MessageQueue、Looper   Android 中的非同步訊息處理主要由四個部分組成,Message、Handler、MessageQueue、Looper。   1. Message: Message 是線上

Android 非同步訊息處理機制 讓你深入理解 Looper、Handler、Message三者關係

很多人面試肯定都被問到過,請問Android中的Looper , Handler , Message有什麼關係?本篇部落格目的首先為大家從原始碼角度介紹3者關係,然後給出一個容易記憶的結論。1、 概述Handler 、 Looper 、Message 這三者都與Android

Android非同步訊息處理機制學習筆記

(一)Handler 什麼是Handler Android訊息機制的上層介面,Handler通過傳送和處理Message和Runnable物件來關聯相對應執行緒的MessageQueeu. 可

Android非同步訊息處理機制詳解

關於Handler例項化的一些關鍵資訊,具體如下: 在主執行緒中可以直接建立Handler物件,而在子執行緒中需要先呼叫Looper.prepare()才能建立Handler物件,否則執行丟擲”

Android非同步訊息處理機制Handler

很多人第一次接觸Handler可能是因為一句話”子執行緒不能操作ui”,那子執行緒能不能操作ui呢?我們在這裡不多討論(其實是可以的,但是執行緒不安全),我們來分析下handler是如何運轉起來的。 一般用法都是在“主執行緒”中new一個handler

Handler非同步訊息處理機制原始碼分析

1. Handler非同步訊息處理機制 主執行緒不能進行耗時操作 (會發生ANR異常) 子執行緒不能更新UI的操作 (因為會報異常——>只有產生該控制元件的執行緒才能操作該控制元件。) 那麼 , 要在子執行緒請求資料,然後將資料傳送到主執行緒中更新

android訊息處理機制——Looper,Handler,Message (原理圖、原始碼

轉自:http://my.oschina.net/u/1391648/blog/282892 在開始討論android的訊息處理機制前,先來談談一些基本相關的術語。   通訊的同步(Synchronous):指向客戶端傳送請求後,必須要在服務端有迴應後客戶端才繼續傳送

Android Handler 非同步訊息處理機制的妙用 建立強大的圖片載入類

                最近建立了一個群,方便大家交流,群號:55032675上一篇部落格介紹了Android非同步訊息處理機制,如果你還不瞭解,可以看:Android 非同步訊息處理機制 讓你深入理解 Looper、Handler、Message三者關係 。那篇部落格的最後,提出可以把非同步訊息處理

Android訊息處理機制:Message、Handlerhe和Looper原始碼解析

android的訊息處理有三個核心類:Looper,Handler和Message。其實還有一個Message Queue(訊息佇列),但是MQ被封裝到Looper裡面了,我們不會直接與MQ打交道,因此我沒將其作為核心類。下面一一介紹: 執行緒的魔法師 Looper Loo

Android中的非同步訊息處理機制

這也是Android中老生常談的一個話題了,它本身並不是很複雜,可是面試官比較喜歡問。本文就從原始碼再簡單的理一下這個機制。也可以說是理一下Handler、Looper、MessageQueue之間的關係。 單執行緒中的訊息處理機制的實現 首先我們以Looper.java原始碼中給出的一個例子來