handler是什么?
handler是Android提供用來更新UI的一套消息機制,也是一套消息處理的機制(發(fā)送和處理消息)
handler原理
handler負責消息發(fā)送,looper負責接收handler發(fā)送過來的消息,并把消息發(fā)送給handler,messageQueue存儲消息的容器
這里先說明一下ThreadLocal,主要在線程中保存變量信息,主要有兩個比較重要的方法,一個是get方法,一個是set方法
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
set方法設置當前線程的值,使用鍵值對的形式存儲Thread和looper之間的關系,Thread作為key,looper作為value
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);
}
get方法就是取出當前線程對應的looper,也就是說ThreadLocal是負責thread和looper之間的關系的
下面看一下Looper.prepare()方法
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));
}
默認情況下ThreadLocal是沒有存儲的,所以要創(chuàng)建一個新的looper
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
從looper方法中,創(chuàng)建了一個MessageQueue,在looper中維護著一個消息隊列
知道了looper和MessageQueue之后,究竟handler跟這兩者有什么關系呢,繼續(xù)看源碼
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;
}
首先調(diào)用Looper.myLooper()
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
獲得當前的looper對象,通過looper拿到MessageQueue,就完成了handler和looper之間的關聯(lián)下面繼續(xù)看handler的消息發(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);
}
先獲得當前的消息隊列,如果隊列為空就拋出異常,不為空,向消息隊列中插入消息
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
插入消息之前就指定消息發(fā)送給誰(msg.target),默認情況下發(fā)送給自己的handler,然后把消息放入隊列中,handler就完成了發(fā)送message到MessageQueue的過程那么消息又是如何輪詢的呢?
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();
}
}
通過myLooper()方法獲取當前l(fā)ooper,進而獲得當前的消息隊列,然后通過MessageQueue的next方法獲取消息,消息為空時返回,不為空時,調(diào)用handler的dispatchMessage(msg)方法,然后這個過程一直循環(huán)
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
首先查看msg.callback是否為空,不為空時去調(diào)用handleCallback(msg),這個方法在handler的構造方法中存在,可以實現(xiàn)消息的攔截;為空只就調(diào)用handleMessage(msg),這個方法都是大家熟悉的,不在描述,整體的handler的原理就描述到這
總結
handler在Android中扮演的非常重要的角色,熟悉handler的原理,不僅在面試的時候有用,就連activity的生命周期也是通過handler發(fā)送消息,詳細請看源碼