一般來說,Handler是Android 消息機制的上層接口,我們經(jīng)常用Handler來處理頁面上的一些交互,主要包括耗時操作完以后,需要在UI層面上進(jìn)行調(diào)整。這里我們就講一講Handler的原理。Handler的原理主要包括三個類,Handler、MessageQueue、Looper
下面是我們使用Handler的一個例子
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
String msgObj = (String) msg.obj;
//更新UI操作
mTextView.setText(msgObj);
break;
}
}
};
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500);
Message message = Message.obtain();
message.what = 1;
message.obj = "Hello World";
mHandler.sendMessage(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
這里我們新創(chuàng)建了一個Handler對象,并重寫了里面的handleMessage(), 然后在我們子線程中創(chuàng)建了一個Message,通過handler.sendMessage(msg) 發(fā)生出去。
Message是一個數(shù)據(jù)類,包含了一些我們常用的屬性。
public final class Message implements Parcelable {
// 可以存儲的幾個屬性
public int what;
public int arg1;
public int arg2;
public Object obj;
Bundle data;
//綁定的Handler
/*package*/ Handler target;
// 指向下一個message
/*package*/ Message next;
public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
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();
}
}
然后我們看一下mHandler.sendMessage(message) 做了什么操作。
//Handler
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull 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(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
//這里比較好理解,給message設(shè)置一個延時的時間,最終會調(diào)用MessageQueue的enqueueMessage().
//MessageQueue
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
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();
return false;
}
msg.markInUse();
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;
}
//這里就是一個入隊的操作,雖然命令是隊列,但是其實就是一個單鏈表,因為message里面有指向下一個message的指針next。入隊操作結(jié)合了delay的時間來進(jìn)行判斷,delay時間短的,插入到前面。這里用鏈表的好處是,比較適合增加、刪除操作。
現(xiàn)在我們的message已經(jīng)插入到MessageQueue里面了,那么里面的message什么時候進(jìn)行分發(fā),傳遞給handler的呢。下面就要講一講Looper了。
剛剛我們的例子是在主線程里面創(chuàng)建Handler的,Android默認(rèn)給主線程創(chuàng)建了Looper對象,這個是在ActivityThread里面。
public static void main(String[] args) {
//創(chuàng)建Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
//開啟loop循環(huán)
Looper.loop();
}
//下面我們來看看Looper里面
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}
//上面new了一個Looper,并保存在sThreadLocal里面
public static void loop() {
final Looper me = myLooper();
me.mInLoop = true;
final MessageQueue queue = me.mQueue;
// 代碼略有刪減,我們主要看for循環(huán)里面
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
//如果我們設(shè)置了observer,這里回調(diào)里面的messageDispatchStarting()
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
//關(guān)鍵是這行代碼,可以看到這里調(diào)用了綁定的handler的dispatchMessage方法
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
msg.recycleUnchecked();
}
}
//下面就是handler里面的dispatchMessage方法,handleMessage這個是不是很熟悉,就是我們創(chuàng)建handler重寫的方法。
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
至此,Handler的消息機制已經(jīng)分析完畢。
另外我想擴(kuò)展一點,就是ThreadLocal這個類,因為我們的looper能夠跨線程通信,就是它的功勞。上面我們講到looper調(diào)用prepare()的時候,我們新創(chuàng)建了一個Looper對象放入到ThreadLocal里面。那么我們來看一下ThreadLocal的get,set操作
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//如果map為空,就創(chuàng)建一個ThreadLocalMap
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
//ThreadLocalMap
static class ThreadLocalMap {
/**
* The table, resized as necessary.
* table.length MUST always be a power of two.
*/
private Entry[] table;
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
}
具體算法這里就不過多闡述,總結(jié)一下就是,ThreadLocal為每一個Thread創(chuàng)建了一個ThreadLocalMap,里面用數(shù)組保存?zhèn)鬟M(jìn)來的值,所以我們在不同的線程去取值的時候,其實我們拿到的是不同的ThreadLocalMap,里面的值也就可能不一樣了,是不是比較簡單?~_~