Android Handler機制系列文章整體內容如下:
- Android Handler機制1之Thread
- Android Handler機制2之ThreadLocal
- Android Handler機制3之SystemClock類
- Android Handler機制4之Looper與Handler簡介
- Android Handler機制5之Message簡介與消息對象對象池
- Android Handler機制6之MessageQueue簡介
- Android Handler機制7之消息發送
- Android Handler機制8之消息的取出與消息的其他操作
- Android Handler機制9之Handler的Native實現前奏之Linux IO多路復用
- Android Handler機制10之Handdler的Native實現Native的實現
- Android Handler機制11之Handler機制總結
- Android Handler機制12之Callable、Future和FutureTask
- Android Handler機制13之AsyncTask源碼解析
本片文章的主要內容如下:
- 1 概述
- 2 相應類的理解
- 3 Handle原理詳解
- 4 主線程的Looper的初始化
一、 概述
工欲善其事必先利其器,在Android的源碼世界里面,有兩大利器,一是Binder IPC機制,關于Binder的內容上面已經講過了。另一個便是Handler消息機制(由Handler/Looper/MessageQueue等構成)。Android有大量的消息驅動方法來進行交互,就像Android的四大組件(Activity、Service、Broadcast、ContentProvider)的啟動過程交互,都離不開Handler的消息機制,所以Android系統某種意義上說也是一種以消息驅動的系統。
那Android為什么要采用Handler的消息機制那?
答: 在Android中,只有主線程才能更新UI,但是主線程不能進行耗時操作,否則會產生ANR異常,所以常常把耗時操作放到其他子線程進程。如果在子線程中需要更新UI,一般都是通過Handler發送消息,主線接受消息并進行相應的邏輯處理。當然除了直接使用Handler,還可以用View的post()方法、Activity的runOnUIThread()方法來更新UI和AsyncTask其實他們本質也是使用了Handler來實現的。后面我們會單獨說他們
要理解Handler的消息機制,就不得不說Handler/Looper/Message/MessageQueue/Message這四4個類,下面我們先大概了解下這幾個類
二、 相應類的理解
關于類的理解,還是以官網上的類介紹為主
(一) Handler
1、什么是Handler
A Handler allows you to send and process Message
and Runnable objects associated with a thread's MessageQueue
. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
簡單翻一下:
Handler是一個可以通過關聯一個消息隊列來發送和處理消息,發送或處理Runnable對象的一個處理程序,每個Handler都關聯一個單個的線程和消息隊列,當你創建一個新的Handler的時候它就將綁定到一個線程或線程上的消息隊列,從那時起,這個Handler就將為這個消息隊列提供消息或Runnable對象,處理消息隊列釋放出來的消息或Runnable對象。
2、Handler有什么用
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
簡單翻譯 一下:
Handler有兩個主要的用途
- 1 安排消息和Runnable對象在未來之星
- 2 將你的一個動作放在不同的線程上執行
3、怎么使用Handler
Scheduling messages is accomplished with the post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler's handleMessage(Message) method (requiring that you implement a subclass of Handler).
翻譯一下:
通過重寫post(Runnable)、postAtTime(Runnable, long)、postDelayed(Runnable, long)、sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message, long)、sendMessageDelayed(Message, long)來完成發送消息。當前版本允許你通過消息隊列接受一個Runnable對象,sendMessage方法當前版本允許你將一個包的數據通過消息隊列的方式處理,但是你需要重寫Handler的handleMessage方法
When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-based behavior.
翻譯一下:
當你發送一個Handler時,你可以使消息隊列(MessageQueue)盡快去處理已經準備好的條目,或者指定一個延遲處理的時間或者指定時間處理,后兩者允許你實現超時,Ticks(系統相對的時間單位)和其他時間段為基礎的行為。
When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. The given Runnable or Message will then be scheduled in the Handler's message queue and processed when appropriate.
即當一個進程被應用程序創建時,它的主線程會運行一個消息隊列負責管理它創建的高層應用程序對象(如Activity、Broadcast Receiver等)和任何它的窗口創建的對象,你可以通過一個Handler,創建自己的線程來實現與主線程之間的交互,但前提是你得在你的線程重寫sendMessage方法并寫上一行行代碼,這樣你給定的Runnable或者Message將被MessageQueue(消息隊列)預定,并在合適的時間處理
注意:有心的同學會注意,我們在進行Handler源碼分析的時候,可以知道Handler中的Message是分2中類型的,一種是Message,就是Message對象,一種是CallMessage,就是Runnable對象,但是MessageQueue中只支持DataMessage,再插入到MessageQueue的時候,會把Runnable對象封裝到Message對象中。
(二) Looper
Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.
Most interaction with a message loop is through the Handler class.
This is a typical example of the implementation of a Looper thread, using the separation of prepare() and loop() to create an initial Handler to communicate with the 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();
}
}
翻譯一下:
用于為線程運行消息循環的類。默認線程沒有與它們相關聯的消息喜歡;所以要在運行循環的線程中調用prepare(),然后調用loop()讓它循環處理消息,直到循環停止。
與消息循環的交互是通過Handler類
下面這個是一個典型的Looper線程實例,它使用prepar()和loop()的分割來創建一個初始的Handler與Looper進行通信。
三、 Handle原理詳解
(一)、模型
Handler的消息機制主要包含:
- Message:消息
- MessageQueue:消息隊列的
- Handler:消息管理類向消息池發送各種消息事件
- Looper:不斷的循環執行(Looper.loop),按分發機制將消息分發給目標處理者
(二)、架構圖
(三)、舉例說明
我們先用一個典型的關于Handler/Looper的線程為例展示
代碼如下:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
//情景1
Looper.prepare();
//情景3
mHandler = new Handler() {
public void handleMessage(Message msg) {
//TODO 定義消息處理邏輯.
//情景4
Message msg=Message.obtain();
}
};
// 情景2
Looper.loop();
}
}
OK,那我們便依照上面的的四個情景依次展開
1、情景1 Looper.prepare();
代碼在Looper.java的82行
/** 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);
}
看下prepare()方法的注釋,翻譯一下:
初始化當前線程和Looper,這樣可以在實際開始啟動循環(loop())之前創建一個Handler并且關聯一個looper。確保在先調用這個方法,然后調用loop()方法,并且通過調用quit()結束。
我們發現prepare()方法里面什么都沒有調用,就是調用了prepare(true),那我們繼續跟蹤下
1.1、 prepare(boolean)方法
這里面的入參boolean表示Looper是否允許退出,true就表示允許退出,對于false則表示Looper不允許退出。
代碼在Looper.java的86行
private static void prepare(boolean quitAllowed) {
//每個線程只允許執行一次該方法,第二次執行的線程的TLS已有數據,則會拋出異常。
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//創建Looper對象,并且保存到當前線程的TLS區域。
sThreadLocal.set(new Looper(quitAllowed));
}
那sThreadLocal是什么?我們來看下
代碼在Looper.java的86行
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
原來是ThreadLocal啊,關于ThreadLocal的內容請參考Android Handler機制2之ThreadLocal
我們看到上面調用了new Looper(quitAllowed),那我們就來看下這個Looper的構造函
1.2、 Looper(boolean)構造函數
private Looper(boolean quitAllowed) {
// 創建MessageQueue對象
mQueue = new MessageQueue(quitAllowed);
// 記錄當前線程
mThread = Thread.currentThread();
}
通過上面代碼,我們發現就是創建了一個MessageQueue,并且把當前線程賦值給本地變量的mThread。
- 1 這樣就實現了Looper和MessageQueue的關聯
- 2 這樣就實現了Thread和Looper的關聯
1.3、 Looper類的思考
因為是構造函數,我們看下Looper這個類的結構,如下圖
咦,大家發現沒,Loop類就一個構造函數,也就是我們上面的說的Looper(boolean) 這個構造函數。而且這個構造函數也是private。我們又發現在這個私有的Looper(boolean)的構造函數,只有在private static void prepare(boolean quitAllowed)調用,而這個靜態方法也是private的,我們看下這個方法在哪里被調用
所以我們得出結論
私有的構造函數 => 私有的靜態方法prepare(boolean) => static prepare()/prepareMainLooper()
所以我們知道,Looper這個類的對象不能直接創建,必須通過Looper來的兩個靜態方法prepare()/prepareMainLooper()來間接創建
1.4、prepareMainLooper()方法
代碼在Looper.java的99行
/**
* 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() {
// 設置不允許退出的Looper
prepare(false);
synchronized (Looper.class) {
//將當前的Looper保存為Looper。每個線程只允許執行一次
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
① 注釋
首先翻譯一下注釋
初始化當前當前線程的looper。并且標記為一個程序的主Looper。由Android環境來創建應用程序的主Looper。因此這個方法不能由咱們來調用。另請參閱prepare()
② 方法解析
- 首先 通過方法我們看到調用了prepare(false);注意這里的入參是false
- 其次 做了sMainLooper的非空判斷,如果是有值的,直接拋異常,因為這個sMainLooper必須是空,因為主線程有且只能調用一次prepareMainLooper(),如果sMainLooper有值,怎說說明prepareMainLooper()已經被調用了,而sMainLooper的賦值是由myLooper來執行,
- 最后調用myLooper()方法來給sMainLooper進行賦值。
③ sMainLooper
上面提到了一個變量時sMainLooper,那sMainLooper到底是什么?我們來看下源代碼.
代碼在Looper.java的 69行
private static Looper sMainLooper; // guarded by Looper.class
通道源碼我們知道原來就是Looper對象啊。但是它是靜態的。而在Java7之前,靜態變量存在永久代(PermGen)。在Hospot JVM上,PermGen 就是方法區;在Java7之后,將變量的存儲轉移到了堆。所以說這個sMainLooper就是主線程的Looper。所以只有通過prepareMainLooper()就可以給主線程Looper賦值了。
1.5、myLooper()方法
代碼在Looper.java的173行
/**
* 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();
}
這里的sThreadLocal.get()是和prepare(boolean)方法里面的sThreadLocal.set(new Looper(quitAllowed));一一對應的。而在prepareMainLooper()方法里面,
提出一個問題,在prepareMainLooper里面調用myLooper(),那么myLooper()方法的返回有沒有可能為null?
答:第一步就是調用prepare(false);,所以說myLooper()這個方法的返回值是一定有值的。
2、情景2 Looper.loop();
代碼在Looper.java的 122行
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
// 獲取TLS存儲的Looper對象
final Looper me = myLooper();
//沒有Looper 對象,直接拋異常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//獲取當前Looper對應的消息隊列
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();
// 進入 loop的主循環方法
// 一個死循環,不停的處理消息隊列中的消息,消息的獲取是通過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
// 默認為null,可通過setMessageLogging()方法來指定輸出,用于debug功能
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// 用于分發消息,調用Message的target變量(也就是Handler了)的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.
// 確保分發過程中identity不會損壞
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
// 打印identiy改變的log,在分發消息過程中是不希望身份被改變
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);
}
// 將Message放入消息池
msg.recycleUnchecked();
}
}
loop進入循環模式,不斷重復下面的操作,直到沒有消息時退出循環
- 讀取MessageQueue的下一條Message
- 把Message分發給相應的target
- 再把分發后的Message回到消息池,以便重復利用
這里有幾個重要方法,我們分別會在后面的文章中說明
- MessageQueue.next()方法: 讀取下一條Message,有阻塞
- 會在Android Handler機制6之MessageQueue簡介中講解MessageQueue.next()方法
- Message.Handler.dispatchMessage(Message msg)方法:消息分發
- 會在Android Handler機制7之消息傳遞流程中講解 Message.Handler.dispatchMessage(Message msg)方法
- Message.recycleUnchecked()方法:消息放入消息池
- 會在Android Handler機制5之Message簡介與消息對象對象池中講解Message.recycleUnchecked()方法
3 Looper的退出循環方法
上面了開啟循環的方法,那么怎么退出循環?Looper里面退出循環有兩個方法分別是quit()和quitSafely()方法
3.1、Looper.quit()方法
代碼在Looper.java的 227行
/**
* Quits the looper.
* <p>
* Causes the {@link #loop} method 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>
*
* @see #quitSafely
*/
public void quit() {
mQueue.quit(false);
}
① 注釋
簡單的翻譯一下:
- 退出循環
- 將終止(loop()方法)而不處理消息隊列中的任何更多消息。在調用quit()后,任何嘗試去發送消息都是失敗的。例如Handler.sendMessage(Message)方法將返回false。因為循環終止之后一些message可能會被無法傳遞,所以這個方法是不安全的??梢钥紤]使用quitSafely()方法來確保所有的工作有序地完成。
② 方法內容:
Looper的quit()方法內部的本質是調用mQueue的quit()的方法,入參是false
3.2、Looper.quitSafely()方法
代碼在Looper.java的 227行
/**
* Quits the looper safely.
* <p>
* Causes the {@link #loop} method to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* However pending delayed messages with due times in the future will not be
* delivered before the loop terminates.
* </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>
*/
public void quitSafely() {
mQueue.quit(true);
}
① 注釋
簡單的翻譯一下:
- 安全退出循環
- 調用quitSafely()方法會使循環結束,只要消息隊列中已經被傳遞的所有消息都將被處理。然而,在循環結束之前,將來不會提交處理延遲消息。
- 調用退出后,所有嘗試去發送消息都將失敗。就像調用Handler.sendMessage(Message)將返回false。
② 方法內容:
Looper的quit()方法內部的本質是調用mQueue的quit()的方法,入參是true
3.3、MessageQueue.quit(boolean)方法
代碼在MessageQueue.java的 413行
void quit(boolean safe) {
//當mQuitAllowed為false,表示不運行退出,強行調用quit()會超出異常
//mQuitAllowed 是在Looper構造函數里面構造MessageQueue()以參數參進去的
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.
//mQuitting=false,那么認定mPtr!=0
nativeWake(mPtr);
}
}
消息退出的方式:
- 當safe=true,只移除尚未觸發的所有消息,對于正在觸發的消息并不移除
- 當safe=false,移除所有消息
4、情景3:創建Handler對象
看到Handler對象,首先要看下Handler的構造函數
好多的構造函數啊,一共7個,其中6個有參的構造函數,1個有參的構造函數,所有的構造函數都是public的,為了大家更好的理解,我將這些構造函數編號如下:
- ① public Handler()
- ② public Handler(Callback callback)
- ③ public Handler(Looper looper)
- ④ public Handler(Looper looper, Callback callback)
- ⑤ public Handler(boolean async)
- ⑥ public Handler(Callback callback, boolean async)
- ⑦ public Handler(Looper looper, Callback callback, boolean async)
上面的7個Handler的構造函數大體上可以分為兩大類:
- 兩個參數的Handler構造函數
- 三個參數的Handler構造函數
4.1 兩個參數的Handler構造函數
這里說一下 ① ② ⑤ ⑥ 這四個是"兩個參數的Handler構造函數",為什么這么說,大家可以看下源碼
4.1.1構造函數①,代碼在Handler.java的 113行
/**
* 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);
}
他內部其實是調用的構造函數⑥,只不過第一個入參為null,第二個參數為false
4.1.2 構造函數②,代碼在Handler.java的 127行
/**
* 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);
}
他內部其實是調用的構造函數⑥,只不過第一個入參為callback,第二個參數為false
4.1.3 構造函數⑤,代碼在Handler.java的 167行
/**
* 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 respect 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);
}
他內部其實是調用的構造函數⑥,只不過第一個入參為null,第二個參數為async
綜上所述我們知道 構造函數① ② ⑤ ,歸根結底都是調用的是構造函數⑥,那我們就來看下構造函數⑥
4.1.4 構造函數⑥,代碼在Handler.java的 188行
/**
* 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 respect 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();
//如果是匿名類、內部類、局不類(方法內部),且沒有聲明為STATIC,則存在內存泄露風險,所以要打印日志提醒開發者
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());
}
}
//獲取當前線程的Looper。
mLooper = Looper.myLooper();
//如果當前線程沒有Looper,則說明沒有調用Looper.prepare(),拋異常
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//把Looper的Queue賦值給Handler的mQueue
mQueue = mLooper.mQueue;
// mCallback 賦值
mCallback = callback;
// mAsynchronous 賦值
mAsynchronous = async;
}
老規矩,先來看下注釋,簡單翻譯如下:
- 使用當前線程的Looper,使用這個指定的Callback接口,并且設置這個handler是否是異步的。
- 除非在構造函數設置為異步的,否則默認的的Handler是同步的。
- 異步消息相對于同步消息的而言的,表示消息不會受到中斷或者事件的影響其全局順序。異步消息是不受到MessageQueue.enqueueSyncBarrier(long)的同步障礙影響。
通過上面代碼我們我們知道
- Handler默認采用的是當前線程TLS中的Looper對象,只要執行了Looper.prepare()方法,就可以可以獲取有效的Looper對象,同時我們上面說了Looper的構造函數關聯了MessageQueue和Thread。而在Handler的構造函數里面Handler里面的MessageQueue即是Looper的MessageQueue。
所以在同一個線程里面(已經調用了Looper.prepare()),Handler里面的MessageQueue和的Looper的MessageQueue指向了同一個對象。
所以我們也說這這個方法讓Handler對象和Looper對象綁定在一起了。
上面提到了Callback,是個什么?讓我們來看下
代碼在Handler.java的 80行
/**
* 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);
}
簡單翻譯一下:
當你實例化Handler的時候可以使用Callback接口,這樣可以避免你自己去去實現Handler的子類
有點復雜,大家怎么理解?大家平時寫Handler不是一般是寫一個匿名內部類居多吧,如下:
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
如果存在一個回調的需求,就可以直接使用Callback了,就不用去實現Handler的子類了。
4.2 三個參數的Handler構造函數
這里說一下③、④、⑦ 這三個是"三個參數的Handler構造函數",為什么這么說,依舊看下源碼
4.2.1構造函數③,代碼在Handler.java的 136行
/**
* 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);
}
他內部其實是調用的構造函數⑦,只不過第一個入參為looper,第二個參數為null,第三個參數為false。
4.2.2構造函數④,代碼在Handler.java的 147行
/**
* 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);
}
他內部其實是調用的構造函數⑦,只不過第一個入參為looper,第二個參數為callback,第三個參數為false。
4.2.3構造函數⑦,代碼在Handler.java的 227行
/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also 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 respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param looper The looper, must not be null.
* @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(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
老規矩,先來看下注釋,簡單翻譯如下:
- 不使用默認的Looper,使用由第一個入參提供的Looper,并采取回調接口Callback來處理消息,同時也可以設置是否是異步的。
- Handler默認是同步的,如果在構造函數里面設置了異步,才會變成異步的。
- 異步消息相對于同步消息的而言的,表示消息不會受到中斷或者事件的影響其全局順序。異步消息是不受到MessageQueue.enqueueSyncBarrier(long)的同步障礙影響。
通過上面代碼我們我們知道
- 首先根據給定的Looper賦值本地變量mLooper和mQueue。這樣實現了Handler和Looper的關聯
4.3 Handler構造函數總結
綜合7個構造函數我們發現其實構造函數的本質都是給下面四個本地變量賦值mLooper、mQueue、mCallback、mAsynchronous。那我們就一次分析下:
- 1、如果在構造函數中沒有給出Looper,則使用默認的Looper,通過Looper.mQueue來給mQueue賦值,實現Handler、Looper、MessageQueue三者綁定。
-通過構造函數來設置Callback的回調接口,不設置則為null
-通告mAsynchronous設控制是同步的還是異步的,而mAsynchronous的值默認是false的,這個mAsynchronous可以通過構造函數來設置。
總結如下:
有同學說圖片看不清,按我就弄個表格
Hander本地變量 | ① Handler() | ② Handler(Callback) | ③ Handler(Looper) | ④ Handler(Looper, Callback) | ⑤ Handler(boolean) | ⑥ Handler(Callback, boolean) | ⑦ Handler(Looper,Callback, boolean) |
---|---|---|---|---|---|---|---|
mLooper(Looper對象) | Looper.myLooper() | Looper.myLooper() | looper | looper | Looper.myLooper() | Looper.myLooper() | looper |
mQueue(MessageQueue對象) | null | callback | null | callback | null | callback | callback |
mAsynchronous(boolean類型) | false | false | false | false | async | async | async |
四、 主線程的Looper的初始化
上面說了很多,那么主線程的Looper是什么時候初始化的那?是在系統啟動的時候,初始化的。
代碼在ActivityThread.java 5401行
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
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());
AndroidKeyStoreProvider.install();
// 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>");
/*** 重點 */
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"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
/*** 重點 */
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
PS:這里補充一個概念ActivityThread不是一個thread,ActivityThread是一個類,大家仔細看他的源代碼ActivityThread并沒有實現Thread,大家千萬不要跑偏了。
通過上面的代碼,我們發現
- 首先調用了Looper的靜態方法prepareMainLooper()給主線程綁定一個Looper,同時設置Looper對應的MessageQueue對象的mQuitAllowed為false,則該messageQueue是不能退出的。
- 其次調用Looper.loop();開啟循環
通過上面兩個步驟開啟了主線程的Hanlder機制