標籤:thread tar lstat its should ring nis course pre
ι 著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Looper在Android的訊息機制中就是用來進行訊息迴圈的。它會不停地迴圈,去MessageQueue中查看是否有新訊息,如果有訊息就立刻處理該訊息,否則就一直等待。
Looper中有一個屬性:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
這也就解釋了,前面我們所說的我們可以通過ThreadLocal實現Looper線上程中的存取。
除此之外,還有兩個屬性需要注意:
final MessageQueue mQueue;final Thread mThread;
下面我們先看下Looper的建構函式:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
在建構函式中,建立了一個MessageQueue訊息佇列,並且將當前線程的對象儲存了起來。
接下來看loop方法,只有調用了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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long traceTag = me.mTraceTag; if (traceTag != 0) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } 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(); } }
loop方法中首先調用了myLooper方法:
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
myLooper方法會返回與當前線程相關聯的Looper對象。如果當前線程沒有關聯任何Looper對象的話,該方法則返回null。
查看loop方法的源碼,可以知道,噹噹前線程沒有關聯任何Looper對象時,loop方法會拋出運行時異常,提示當前線程中沒有Looper。若想解決該問題,可以在loop方法被調用前,先執行Looper.prepare()方法,建立一個looper對象。繼續看loop方法的源碼,可以看到該方法是一個死迴圈,唯一可以跳出該迴圈的方法就是queue.next()返回的對象為null。在上面的文章中,我們分析過,queue.next()即讀取MessageQueue中的訊息,next()方法返回null,說明MessageQueue中沒有Message,即該MessgaeQueue調用了quit方法。那麼何時MessageQueue會調用quit方法呢?來看下Looper的quit方法:
public void quit() { mQueue.quit(false);}
以及Looper的quitSafely方法:
public void quitSafely() { mQueue.quit(true); }
Looper的quit方法和quitSafely方法都會導致MessageQueue調用quit方法,所以當不需要Looper的時候,建議調用Looper的quit()方法或quitSafely()方法,以避免loop方法無限迴圈下去。
要想知道Looper的quit方法和quitSafely方法的區別,我們看下MessgaeQueue的quit方法:
void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } // We can assume mPtr != 0 because mQuitting was previously false. nativeWake(mPtr); } }
安全退出,則調用removeAllFutureMessagesLocked()方法,該方法會設定一個標記,當訊息佇列中的已有訊息全部處理完畢後才會安全退出;quit則會調用removeAllMessagesLocked(),直接退出。
下面接著看loop方法,重點看這一句:
msg.target.dispatchMessage(msg);
在Android的訊息機制概述中,我們已經說過,target是Message的一個屬性,其類型為Handler,msg.target也就是發送這條訊息的對象。由此一來,Handler發送的Message最終又交給了它自己來調用dispatchMessage方法來處理,但是dispatchMessage方法是在Looper的loop方法中被調用的,那麼Looper的loop方法是在哪裡執行的呢?在建立Handler時所在的線程中執行的。
ActivityThread(主線程)在建立時,會初始化Looper,所以我們可以在主線程中直接使用Handler,當需要更新UI時,可以通過Handler發送訊息,最後就可以回到主線程去更新UI啦,啦啦啦。
除此之外,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(); } }
該方法會執行個體化當前線程作為一個looper,但是是主線程的looper啦。Android系統會為我們建立主線程的looper,我們也不需要自己手動去調用該方法了。該方法的實質還是通過prepare方法實現的。
再如getMainLooper方法:
/** * Returns the application‘s main looper, which lives in the main thread of the application. */ public static Looper getMainLooper() { synchronized (Looper.class) { return sMainLooper; } }
該方法使得我們可以在任何地方擷取到主線程的Looper了。
【原創】源碼角度分析Android的訊息機制系列(五)——Looper的工作原理