Android Handler訊息機制學習
阿新 • • 發佈:2018-11-12
1.概述
Handler允許你傳送和處理Message,以及和執行緒相關聯的Runnable物件。每一個Handler例項都與一個執行緒及該執行緒的MessageQueue相關聯。既當你建立一個Handler時,該Handler必須繫結一個執行緒以及該執行緒的訊息佇列,一旦它被建立,它能把messages和runnables傳送到message queue,並在它們從message queue中出來的時候執行它們。
Handler主要有兩個主要用途:
- 在未來的某個時間點排程messages和runnables的執行
- 將要在不同執行緒上執行的操作加入佇列
當你的應用程式被創建出來的時候,主執行緒會專門執行一個message queue來管理最頂級的應用物件(如activities, broadcast receivers,等等)以及它們建立的任何其它視窗。你可以建立你自己的執行緒,通過Handler來與主執行緒建立聯絡
2.原始碼分析
2.1 MessageQueue-訊息佇列
MessageQueue是一個通過Looper分發它持有的訊息列表的低層級類。Messages沒有直接新增到MessageQueue中,而是通過與Looper相關聯的Handler物件。
- Message-訊息
該類實現了Parcelable介面,你可以把它看作一個數據類
**
*
* Defines a message containing a description and arbitrary data object that can be
* sent to a {@link Handler}. This object contains two extra int fields and an
* extra object field that allow you to not do allocations in many cases.
* 定義包含描述和任意資料物件的訊息
* 傳送到Handler。這個物件包含兩個額外的int欄位和一個
* 額外的物件欄位,允許您在很多情況下不進行分配。
* <p class="note" >While the constructor of Message is public, the best way to get
* one of these is to call {@link #obtain Message.obtain()} or one of the
* {@link Handler#obtainMessage Handler.obtainMessage()} methods, which will pull
* them from a pool of recycled objects.</p>
* 注意:不要直接使用New Message()建立Message物件,最好的方式是通過Handler.obtainMessage()
* 方法,它會從物件回收池中拉取該訊息物件
*/
public final class Message implements Parcelable {
/** @hide */
public static final Object sPoolSync = new Object();
/**
* 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;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
**
* Same as {@link #obtain()}, but sets the value for the target member on the Message returned.
* 與obtain()相同,但在返回的訊息上設定目標成員的值。
* @return A Message object from the global pool.
* 返回來自全域性池的訊息物件
*/
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;//接收傳遞過來的Handler
return m;
}
}
複製程式碼
2.2 Looper-訊息輪詢器
Looper用於為執行緒輪詢messages。執行緒預設是沒有與之相關聯的Lopper,我們必須通過Looper.prepare()方法去建立它。示例:
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();
}
}
複製程式碼
- ThreadLocal提供執行緒的區域性變數,通過它訪問執行緒獨立初始化變數的副本。即Looper通過ThreadLocal類來與當前執行緒進行互動
//私用構造方法
//quitAllowed是否允許退出
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//例項化訊息佇列
mThread = Thread.currentThread();//獲取當前執行緒
}
/** 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()}.
* 初始化當前執行緒的Looper
* 在它準備輪詢之前,給你一個時機點去建立一個Handler並引用它
* 呼叫該方法後一定記得Looper.loop()方法,並結束的時候呼叫Looper.quit()方法退出
*/
public static void prepare() {
prepare(true);
}
// sThreadLocal.get() will return null unless you have called prepare().
//必須先呼叫Looper.prepare()方法,否則返回空
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
//每一個執行緒只能有唯一的一個looper
if (sThreadLocal.get() != null) {//不為空丟擲異常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));//設定Looper
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
* 返回與當前執行緒關聯的looper
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
/**
* 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();//獲取looper
if (me == null) {//為空則丟擲異常
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//獲取looper的訊息佇列
// 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();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
for (;;) {//無限輪詢
Message msg = queue.next(); // might block
if (msg == null) { //沒有message則不往下執行
// No message indicates that the message queue is quitting.
return;
}
***省略程式碼***
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
try {
msg.target.dispatchMessage(msg);//呼叫Handler的dispatchMessage(msg)方法
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//回收可能正在使用的訊息。
//在處理訊息佇列時,MessageQueue和Looper在內部使用。
msg.recycleUnchecked();
}
}
//sThreadLocal.get()
public T get() {
Thread t = Thread.currentThread();//通過Thread的靜態方法獲取當前的執行緒
//ThreadLocalMap是一個定製的HashMap(),僅適用於維護執行緒區域性值,每一個執行緒都持有一個ThreadLocalMap物件
ThreadLocalMap map = getMap(t);//傳入當前執行緒獲取當前執行緒的ThreadLocalMap物件
-------------------------------------------------------------------------------—————————————
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
-------------------------------------------------------------------------------—————————————
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
複製程式碼
2.3 Handler
2.3.1 建立Handler物件
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
* 如果你不想通過繼承Handler來實現,你必須實現Callback介面
*/
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public boolean handleMessage(Message msg);
}
//預設構成器
//如果該Handler所繫結的執行緒沒有looper,它將收不到任何messages,並且會丟擲異常
public Handler() {
this(null, false);
}
//預設構造器的Callback為空,所以當我們通過new Handler()來建立例項時,
//我們必須重寫Handler的handleMessage(Message msg)方法,即:
companion object {//注意寫成靜態內部類的形式,避免記憶體洩漏
private class MyHandler :Handler(){
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
}
}
}
-------------------------------------------------------------------------------—————————————
//主動實現Callback介面,來建立Handler例項
public Handler(Callback callback) {
this(callback, false);
}
companion object {
private val mHandler1:Handler = Handler(object :Handler.Callback{
override fun handleMessage(msg: Message?): Boolean {
return true
}
})
或
private val mHandler2:Handler = Handler(Handler.Callback {
true
})
}
-------------------------------------------------------------------------------—————————————
/**
* Use the provided {@link Looper} instead of the default one.
*
* @param looper The looper, must not be null.
* //不使用預設的looper
*/
public Handler(Looper looper) {
this(looper, null, false);
}
//之前我看到某些前輩是通過下面這種方式來建立Handler例項,通過傳遞主執行緒的looper
//但這是沒必要的,Handler預設就是使用主執行緒的looper(下面會分析)
//並且原始碼註釋也說了,使用你自己的提供的looper而不是預設的
private val mHandler:Handler = object :Handler(Looper.getMainLooper()){
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
}
}
-------------------------------------------------------------------------------—————————————
//該構造同上,如果你不想重寫handleMessage(msg: Message?)方法,那麼你就重寫Callback介面
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
//是否需要非同步處理messages,預設是非同步的
public Handler(boolean async) {
this(null, async);
}
//自己提供looper,實現Callback介面,決定是否非同步
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
-------------------------------------------------------------------------------—————————————
/*
* Set this flag to true to detect anonymous, local or member classes
* that extend this Handler class and that are not static. These kind
* of classes can potentially create leaks.
* 將此標誌設定為true以檢測匿名類、本地類或成員類
* 繼承了Handler不是靜態的,可能存在記憶體洩漏
*/
private static final boolean FIND_POTENTIAL_LEAKS = false;
//通過Handler()、Handler(Callback callback)、Handler(boolean async)
//都會呼叫該構造器
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {//檢查可能存在的記憶體洩漏,預設是false
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();//獲取looper
if (mLooper == null) {//如果為空丟擲異常
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//獲取Looper中的訊息佇列
mCallback = callback;
mAsynchronous = async;
}
private static void handleCallback(Message message) {
message.callback.run();//執行Message持有的Runnable
}
/**
* Handle system messages here.
* 處理系統Messages
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {//如果Message的Runnable不為空
handleCallback(msg);呼叫Handler的handleMessage(msg)方法處理Message
} else {
if (mCallback != null) {//如果Handler的Callback不為空
if (mCallback.handleMessage(msg)) {//呼叫Callback的handleMessage(msg)方法
return;
}
}
//否則呼叫Handler的handleMessage(msg)方法
handleMessage(msg);
}
}
複製程式碼
2.3.2 建立Message物件
public final Message obtainMessage()
{
return Message.obtain(this);
}
public final Message obtainMessage(int what)
{
return Message.obtain(this, what);
}
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
public final Message obtainMessage(int what, int arg1, int arg2)
{
return Message.obtain(this, what, arg1, arg2);
}
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
return Message.obtain(this, what, arg1, arg2, obj);
}
複製程式碼
2.3.3 傳送Message
/**
* 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.
* 將Runnable新增到訊息佇列中。
* runnable將在此Handler所在的執行緒上執行。
*
* @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.
* Runnable成功新增到訊息佇列中返回ture,失敗返回false
*/
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();建立Message物件
m.callback = r;把Runnale傳遞給Message
return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {//延遲時間小於0,則置為0
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//延遲傳送
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postDelayed(Runnable r, Object token, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//把當前的Handler傳遞給Message的Handler
if (mAsynchronous) {//是否非同步
msg.setAsynchronous(true);
}
//最終呼叫MessageQueue的enqueueMessage方法
return queue.enqueueMessage(msg, uptimeMillis);
}
MessageQueue:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {//Message的Handler為空,丟擲異常
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {//Message正在使用,丟擲異常
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(TAG, e.getMessage(), e);
msg.recycle();//回收Message
return false;
}
msg.markInUse();設定Message是否正在使用的Flag
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;
}
複製程式碼