[Android] android的消息隊列機制

android下的線程,Looper線程,MessageQueue,Handler,Message等之間的關係,以及Message的send/post及Message dispatch的過程。 java

Looper線程

我 們知道,線程是進程中某個單一順序的控制流,它是內核作CPU調度的單位。那何爲Looper線程呢?所謂Looper線程,便是藉助於Looper和 MessageQueue來管理控制流的一類線程。在android系統中,application的主線程便是藉助於Looper和 MessageQueue來管理控制流的。其實,不單單隻有主線程能夠用Looper和MessageQueue來管理控制流,其餘的線程也同樣能夠。我 們能夠先看一下android source code的註釋中給出的一種Looper線程的實現方式:android

package com.example.messagequeuedemo;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

public class LooperThread extends Thread {
    public static final String TAG = MainActivity.TAG;
    private static final String CompTAG = "<span></span>LooperThread<span></span>";

    public Handler mHandler;

    @Override
    public void run() {
        Log.d(TAG, CompTAG + ": LooperThread=>run");
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(android.os.Message msg) {
                Log.d(TAG, CompTAG + ": LooperThread=>Handler=>handleMessage");
                // process incoming message here
            }
        };

        Looper.loop();
    }
}

能夠看到,就是在線程的run()方法中,調用Looper.prepare() 作一些初始化,而後建立一個Handler對象,最後執行Looper.loop()即開始了整個的事件循環。就是這麼的簡單,一個可使用消息隊列來管 理線程執行流程的Looper 線程就建立好了。 算法

接着咱們來看一下,神祕的Looper.prepare()到底都幹了些什麼事情: app

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

/** 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");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}


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

可 以看到,它作的事情就是爲當前的線程建立了一個Looper對象,並存儲在一個靜態的線程局部變量中。在Looper的構造函數中建立了 MessageQueue,同時Looper會引用到當前的線程,並將一個表示狀態的變量mRun設置爲true。對於此處的線程局部變量 sThreadLocal,能夠理解爲就是一個HashMap,該HashMap中存放的數據其類型爲Looper,而HashMap的key則 Thread.currentThread()。 less

啓動Looper線程就和啓動普通的線程同樣,好比: async

public class MainActivity extends Activity {
    public static final String TAG = "MessageQueueDemo";
    private static final String CompTAG = "MainActivity";
    private LooperThread mLooperThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, CompTAG + ": MainActivity=>onCreate");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLooperThread = new LooperThread();
        mLooperThread.start();
    }

一樣是new一個Thread對象,而後執行該對象的start()方法。 ide

其實Looper線程有兩種,一種就是咱們上面看到的那種普通的Looper線 程,另一種則是main loop線程,建立前者使用咱們前面看到的Looper.prepare()方法,而要建立後者,咱們則可使用 Looper.prepareMainLooper()方法。能夠看一下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();
    }
}

比較特別的地方即在於,此處調用prepare()方法傳進去的參數爲false,即表示這個Looper不可以被quit掉。其餘卻是基本同樣。整個android系統中,調用到prepareMainLooper()方法的大概有兩處:oop

/frameworks/base/services/java/com/android/server/
H A D    SystemServer.java    94 Looper.prepareMainLooper();
/frameworks/base/core/java/android/app/
H A D    ActivityThread.java    5087 Looper.prepareMainLooper();

一處在ServerThread的run()方法中,用於爲system server主線程初始化消息隊列等,另一處在ActivityThread的run()方法中,天然便是建立android app主線程的消息隊列了。 post

經過消息與Looper線程交互

那 Looper線程的特別之處究竟在哪裏呢?如前所述,這種線程有一個Looper與之關聯,這種線程會使用消息隊列,或者稱爲事件循環來管理執行的流程。 那這種特別之處又如何體現呢?其餘線程能夠向此類線程中丟消息進來,固然此類線程自己也能夠往本身的消息隊列裏面丟消息,而後在事件循環中,這種事件會得 到有效的處理。那究竟要如何往Looper線程的消息隊列中發送消息呢?

回憶咱們前面建立Looper線程的那個code,咱們不是有建立出來一個Handler嘛。沒錯,咱們就是經過Handler來向Looper線程的MessageQueue中發送消息的。能夠看一下code的寫法。先是LooperThread的寫法:

package com.intel.helloworld;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

public class LooperThread extends Thread {
    private static final String TAG = MainActivity.TAG;
    private static final String CompTAG = "LooperThread";
    public Handler mHandler;

    @Override
    public void run() {
        Log.d(TAG, CompTAG + ": " + "LooperThread-->run");
        Looper.prepare();

        mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // process incoming message
                Log.d(TAG, CompTAG + ": " + "Handler-->handleMessage, msg.what = " + msg.what);
            }
        };

        Looper.loop();
    }

    public Handler getHandler() {
        return mHandler;
    }
}

而後是向Looper線程發送消息的部分的寫法:

package com.intel.helloworld;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity {
    public static final String TAG = "LifecycleDemoApp";
    private static final String CompTAG = "MainActivity";
    
    public static final int MESSAGE_WHAT_CREATE = 1;
    public static final int MESSAGE_WHAT_START = 2;
    public static final int MESSAGE_WHAT_RESUME = 3;
    public static final int MESSAGE_WHAT_PAUSE = 4;
    public static final int MESSAGE_WHAT_STOP = 5;
    public static final int MESSAGE_WHAT_DESTROY = 6;

    LooperThread mThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, CompTAG + ": " + "Activity-->onCreate");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mThread = new LooperThread();
        mThread.start();
    }

    @Override
    protected void onStart() {
        Log.d(TAG, CompTAG + ": " + "Activity-->onStart");
        super.onStart();

        Handler handler = mThread.mHandler;
        Message msg = Message.obtain();
        msg.what = MESSAGE_WHAT_START;
        handler.sendMessage(msg);
    }
    
    @Override
    protected void onResume() {
        Log.d(TAG, CompTAG + ": " + "Activity-->onResume");
        super.onResume();

        Handler handler = mThread.mHandler;
        Message msg = Message.obtain();
        msg.what = MESSAGE_WHAT_RESUME;
        handler.sendMessage(msg);
    }
    
    @Override
    protected void onPause() {
        Log.d(TAG, CompTAG + ": " + "Activity-->onPause");
        super.onPause();

        Handler handler = mThread.mHandler;
        Message msg = Message.obtain();
        msg.what = MESSAGE_WHAT_PAUSE;
        handler.sendMessage(msg);
    }
    
    @Override
    protected void onStop() {
        Log.d(TAG, CompTAG + ": " + "Activity-->onStop");
        super.onStop();

        Handler handler = mThread.mHandler;
        Message msg = Message.obtain();
        msg.what = MESSAGE_WHAT_STOP;
        handler.sendMessage(msg);
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, CompTAG + ": " + "Activity-->onDestroy");
        super.onDestroy();

        Handler handler = mThread.mHandler;
        Message msg = Message.obtain();
        msg.what = MESSAGE_WHAT_DESTROY;
        handler.sendMessage(msg);
    }

    @Override<span style="color:#E53333;"></span> public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        Log.d(TAG, CompTAG + ": " + "Activity-->onSaveInstanceState");
        super.onSaveInstanceState(outState);
    }
}

向一個Looper線程發送消息的過程,基本上便是,調用Message.obtain()或Handler.obtainMessage()獲取一個Message對象->設置Message->調用 Looper線程中建立的Handler對象來發送消息。

Handler 到底是如何知道要向哪一個MessageQueue中發送消息呢,從前面的code中,咱們找不到任何將Handler與特定的MessageQueue關 聯起來的代碼,這到底是怎麼回事呢?這也是咱們強調要使用Looper線程中建立的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);
}

/**
 * Constructor associates this handler with the {@link Looper} for the
 * current thread and takes a callback interface in which you can handle
 * messages.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 *
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Callback callback) {
    this(callback, false);
}

/**
 * Use the provided {@link Looper} instead of the default one.
 *
 * @param looper The looper, must not be null.
 */
public Handler(Looper looper) {
    this(looper, null, false);
}

/**
 * Use the provided {@link Looper} instead of the default one and take a callback
 * interface in which to handle messages.
 *
 * @param looper The looper, must not be null.
 * @param callback The callback interface in which to handle messages, or null.
 */
public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

/**
 * Use the {@link Looper} for the current thread
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with represent to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier long)}.
 *
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
public Handler(boolean async) {
    this(null, async);
}

/**
 * Use the {@link Looper} for the current thread with the specified callback interface
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with represent to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier long)}.
 *
 * @param callback The callback interface in which to handle messages, or null.
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
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;
}

能夠看到,很簡單,是經過Looper.myLooper()獲取到當前線程的 Looper對象,並與相關的MessageQueue等關聯起來的。這也是前面咱們在實現Looper線程時,要在其run方法中建立一個public 的Handler的依據。固然,咱們也能夠在構造Handler對象時,顯式地使其與特定的Looper對象關聯起來。

Handler提供了兩組函數用於向一個Looper線程的MessageQueue中發送消息,分別是postXXX()族和sendXXX()族。能夠先看一下sendXXX()族的實現:

/**
 * Pushes a message onto the end of the message queue after all pending messages
 * before the current time. It will be received in {@link #handleMessage},
 * in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}

/**
 * Sends a Message containing only the what value.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean sendEmptyMessage(int what)
{
    return sendEmptyMessageDelayed(what, 0);
}

/**
 * Sends a Message containing only the what value, to be delivered
 * after the specified amount of time elapses.
 * @see #sendMessageDelayed(android.os.Message, long) 
 * 
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

/**
 * Sends a Message containing only the what value, to be delivered 
 * at a specific time.
 * @see #sendMessageAtTime(android.os.Message, long)
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */

public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageAtTime(msg, uptimeMillis);
}

/**
 * Enqueue a message into the message queue after all pending messages
 * before (current time + delayMillis). You will receive it in
 * {@link #handleMessage}, in the thread attached to this handler.
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

/**
 * Enqueue a message into the message queue after all pending messages
 * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
 * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
 * You will receive it in {@link #handleMessage}, in the thread attached
 * to this handler.
 * 
 * @param uptimeMillis The absolute time at which the message should be
 *         delivered, using the
 *         {@link android.os.SystemClock#uptimeMillis} time-base.
 *         
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.  Note that a
 *         result of true does not mean the message will be processed -- if
 *         the looper is quit before the delivery time of the message
 *         occurs then the message will be dropped.
 */
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);
}

/**
 * Enqueue a message at the front of the message queue, to be processed on
 * the next iteration of the message loop.  You will receive it in
 * {@link #handleMessage}, in the thread attached to this handler.
 * <b>This method is only for use in very special circumstances -- it
 * can easily starve the message queue, cause ordering problems, or have
 * other unexpected side-effects.</b>
 *  
 * @return Returns true if the message was successfully placed in to the 
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
public final boolean sendMessageAtFrontOfQueue(Message msg) {
    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);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

繞來繞去,最終都是調用MessageQueue的 enqueueMessage()方法來將一個Message放入一個MessageQueue中。值得注意的是,在 Handler.enqueueMessage()中,會將Message的target設置爲this,這其實是決定了Looper的消息循環中,在 dispatch/handle message時將會使用的Handler。即,在default狀況下,處理message的那個handler也將會是發送此message的 handler。

Handler實際的職責,並不像它的名稱所顯示的那樣,其實它不單單是處理message,它還負責發送Message給線程的MessageQueue。

再來看一下MessageQueue的enqueueMessage()方法的code:

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

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

        msg.when = when;
        Message p = mMessages;
        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;
        }
    }
    if (needWake) {
        nativeWake(mPtr);
    }
    return true;
}

整個將Message放入MessageQueue的算法也還算比較清晰簡潔,並 沒有什麼太繞的地方。此處咱們能夠一覽MessageQueue中保存Messages的結構,即,MessageQueue用一個單向鏈表來保存全部的 Message,而鏈表中各個Message則按照其請求的執行時間前後來排列。

向Looper 線程的MessageQueue中發送消息的另一族方法postXXX(),其實現同前面的sendXXX()族方法也大同小異啦:

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is
 * attached.
 *
 * @param r The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */
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;
}

Post的message,其callback將是傳入的Runnable對象,其餘就與send的message同樣了。

消息隊列中消息的處理

消息隊列中的消息是在Looper.loop()中被處理的:

/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
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;

    // 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();

    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);
        }

        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.recycle();
    }
}

這個函數會調用Handler的dispatchMessage()方法來處理消息,其實也就是msg.target對象的dispatchMessage()方法。 此外咱們能夠看到,在Looper.loop()方法的末尾recycle了從MessageQueue中取出的已經dispatch的消息。從而,咱們 須要經過Handler向一個Looper線程的MessageQueue中發送消息時,咱們只要obtain一個Message而後發送就行了,而不需 要本身手動去recycle,這些事情將會由Looper來幫助咱們完成。接着來看Handler. dispatchMessage()的實現:

/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

在Message的callback成員爲非空時,會執行 handleCallback(msg),不然的話會依據Handler的mCallback是否爲空來肯定是否要執行 mCallback.handleMessage(msg),並執行Handler的handleMessage(msg)。Handler的handleMessage()方法一般須要override,來實現消息處理的主要邏輯。而mCallback則使得開發者能夠比較容易的添加一種對Message作一些額外檢測的機制,以提高消息處理的效率。

接着咱們看一下,Handler.handleCallback(msg)的實現:

private static void handleCallback(Message message) {
    message.callback.run();
}
相關文章
相關標籤/搜索