標籤:android handler looper messagequeue
上一篇文章,我們講到在調用Handler的sendMessage方法時,最終我們會進入到一個叫 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); }
在這裡,我們看到了MessageQueue和enqueueMessage等變數跟方法,我們可以想到,在Handler的實現的機制中,一定存在著一個訊息佇列,而它存放了我們建立的眾多訊息(Message)對象。
從這裡,我們就會開始去探尋隱藏在 Handler對象後面的那一些我們想知道的實現機制了。
首先,我們還是從 Handler的建立開始說起,在上一篇文章,我們是通過 new Handler的方法來建立的,代碼如下:
private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case MSG_ID_1: Log.v("Test", "Toast called from Handler.sendMessage()"); break; case MSG_ID_2: String str = (String) msg.obj; Log.v("Test", str); break; } } };
顯然,我們要去看一下Handler的建構函式,如下:
public Handler() { this(null, false); } public Handler(Callback callback) { this(callback, false); } public Handler(Looper looper) { this(looper, null, false); } public Handler(Looper looper, Callback callback) { this(looper, callback, false); } public Handler(boolean async) { this(null, async); } 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; } public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
我們可以看到,真正實現的建構函式,其實只有下面兩個,如下:
public Handler(Callback callback, boolean async) { .... } public Handler(Looper looper, Callback callback, boolean async) { ... }
這兩個的差別就在於是否有參數Looper,而Looper是一個線程相關的對象。
何謂線程相關的變數?就是線程間不能共用的對象,只在本線程內有作用的對象。
那麼Looper對象的作用是什嗎?
從我個人的理解,Looper類就是對MessageQueue的封裝,它主要做的是兩件事:
1)構造Looper對象,初始化MessageQueue,我們可以從其建構函式看到:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
顯然,MessageQueue正是在建立Looper的時候初始化的。
我們還注意到,這個建構函式是private的,而它則是被Looper.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)); }
可以看到,Loop對象被建立之後,會被放到ThreadLocal變數中,而ThreadLocal正是線程局部變數,這說明了關於Looper的一個特性:
每一個線程中都只能有一個Looper對象。
2)調用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; .... 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.recycle(); } }
從上面的代碼中,我們可以看到,在一個無限迴圈中,會從MessageQueue中獲得訊息,然後通過msg.target.dispatchMessage(msg)方法調用,處理訊息,最後將訊息進行回收。
在這裡,我們先不關心dispatchMessage方法,我們先跑一下題,看一下recycle方法裡面做了什麼事吧,如下:
private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; /** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. */ public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; sPoolSize--; return m; } } return new Message(); } public void recycle() { clearForRecycle(); synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
從上面的代碼中,我們可以看到,Message對象本身有一個next的欄位指向另外一個Message,也就是說,可以通過鏈表的方式將眾多的Message給串起來,變成一個鏈表的訊息池sPool。
而在這裡,當調用recycle方法,就會將當前Message對象,先clearForRecycle之後,再添加到 sPool的頭部中,而當我們通過Message的obtain方法的時候,我們其實也是從sPool中拿 出一個空的Message對象。
相信看到這裡,大家就瞭解了上一篇文章中我說,為什麼建議大家使用Message.obtain方法去擷取訊息對象了吧。
接下來,我們再回到正題上。
從上面關於Handler的建立和關於Looper的描述中,我們可以得出這樣一個結論:
在每一個線程中,如果我們要建立Handler,那麼此線程中就必須有一個Looper對象,而這個Looper對象中又封裝了一個MessageQueue對象來對Message進行管理。
所以,如果我們要在一個新線程中使用handler的話,我們就必須通過調用Loop.prepare()方法,為此線程建立一個Looper對象,官方給出的代碼如下:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
當然,只有理論當然是不行的,我們還是得通過一個例子來看一下具體的效果,如下:
public class MainActivity extends ActionBarActivity { private static final int MSG_ID_1 = 1; private static final int MSG_ID_2 = 2; class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId()); switch (msg.what) { case MSG_ID_1: Log.v("Test", "Toast called from Handler.sendMessage()"); break; case MSG_ID_2: String str = (String) msg.obj; Log.v("Test", str); break; } } }; Looper.loop(); } } protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId()); LooperThread looperThread = new LooperThread(); looperThread.start(); while(looperThread.mHandler == null){ } Message message = Message.obtain(); message.what = MSG_ID_1; looperThread.mHandler.sendMessage(message); Message msg2 = Message.obtain(); msg2.obj = "I'm String from Message 2"; msg2.what = MSG_ID_2; looperThread.mHandler.sendMessage(msg2); }}
對應的結果如下:
10-27 16:48:44.519: V/Test(20837): Id of MainThread : 110-27 16:48:44.529: V/Test(20837): Id of LooperThread : 6842110-27 16:48:44.529: V/Test(20837): Toast called from Handler.sendMessage()10-27 16:48:44.529: V/Test(20837): Id of LooperThread : 6842110-27 16:48:44.529: V/Test(20837): I'm String from Message 2
那其實在這裡有一個問題,為什麼我們平常可以直接去建立Handler對象,而不需要去調用UI線程的Looper.prepare和loop等方法呢?
當然,這肯定也是需要的,只是這一步是由Android系統幫我們做了,所以預設的主線程就不再需要去做這些初始化。
好了,這一篇文章,我們就瞭解了關於線程,Looper,Handler, MessageQueue 和 Message 等之間的一些關聯,而主要是對於Looper對象的認識。
結束。
Android中利用Handler實現訊息的分發機制(一)