Handler消息機(jī)制解析
Android提供用來更新UI的一套機(jī)制,也是一套消息處理機(jī)制,可以發(fā)送消息和處理消息。
Handler
Handler對(duì)象來與Looper溝通,以便push新消息到MessageQueue里;或者接收Looper從Message Queue取出)所送來的消息。
方法
-
構(gòu)造方法
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; }
幾個(gè)構(gòu)造方法最終都會(huì)調(diào)用這個(gè)構(gòu)造方法,myLooper()
。獲取當(dāng)前Looper對(duì)象,通過looper獲取MessageQueue,完成了handler和looper的關(guān)聯(lián)
-
消息發(fā)送方法
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); }
如果隊(duì)列為null
就拋異常,否則向隊(duì)列中放入消息。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
放入消息的時(shí)候要指定目標(biāo),默認(rèn)是發(fā)送個(gè)自己。
消息放入隊(duì)列后,Looper通過looper()
處理消息隊(duì)列
-
分發(fā)消息方法
/** * 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); } }
在這個(gè)方法內(nèi)調(diào)用handleCallback
方法處理消息
內(nèi)部接口Callback
public interface Callback {
public boolean handleMessage(Message msg);
}
Looper
一個(gè)線程只能產(chǎn)生一個(gè)Looper對(duì)象,由它來管理此線程里的MessageQueue(消息隊(duì)列)。
- 內(nèi)部包含了一個(gè)消息隊(duì)列
MessageQueue
所有handler發(fā)送的消息都通過這個(gè)隊(duì)列。 - Looper.Looper方法是一個(gè)死循環(huán),不斷從
MessageQueue
中取Message,有就處理,沒有就阻塞
Looper類的方法
-
Looper.prepare()方法(調(diào)用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)); }
這個(gè)方法創(chuàng)建新的Looper
,如果一個(gè)線程中已經(jīng)有一個(gè)Looper就會(huì)報(bào)錯(cuò),如果沒有就調(diào)用私有構(gòu)造方法創(chuàng)建一個(gè)新的Looper
-
私有的構(gòu)造方法
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
創(chuàng)建了一個(gè)MessageQueue
,并關(guān)聯(lián)當(dāng)前Thread
-
myLopper()
/** * 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(); }
獲取當(dāng)前Looper對(duì)象,
-
myQueue()
/** * Return the {@link MessageQueue} object associated with the current * thread. This must be called from a thread running a Looper, or a * NullPointerException will be thrown. */ public static @NonNull MessageQueue myQueue() { return myLooper().mQueue; }
獲取Looper中的MessageQueue
-
死循環(huán)方法 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.recycleUnchecked(); } }
這個(gè)方法用于處理隊(duì)列中的消息:通過myLooper()方法獲取單前的Looper
,從而獲取當(dāng)前的消息隊(duì)列,通過消息隊(duì)列的next()
方法獲取消息,消息不為null的時(shí)候調(diào)用handler的dispatchMessage(msg)
方法
MessageQueue消息隊(duì)列
存儲(chǔ)消息的容器
ThreadLocal class
作用:在線程中保存信息變量。負(fù)責(zé)thread和looper之間的關(guān)系
方法
-
set
public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); }
鍵值對(duì)的形式存儲(chǔ)Thread和Looper之間的關(guān)系,Thread是key,Looper是值
-
get
public T get() { // Optimized for the fast path. Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { Object[] table = values.table; int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { values = initializeValues(currentThread); } return (T) values.getAfterMiss(this); }
取出當(dāng)前線程對(duì)應(yīng)的looper。