一般来说,Handler是Android 消息机制的上层接口,我们经常用Handler来处理页面上的一些交互,主要包括耗时操作完以后,需要在UI层面上进行调整。这里我们就讲一讲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();
这里我们新创建了一个Handler对象,并重写了里面的handleMessage(), 然后在我们子线程中创建了一个Message,通过handler.sendMessage(msg) 发生出去。
Message是一个数据类,包含了一些我们常用的属性。
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设置一个延时的时间,最终会调用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。入队操作结合了delay的时间来进行判断,delay时间短的,插入到前面。这里用链表的好处是,比较适合增加、删除操作。
现在我们的message已经插入到MessageQueue里面了,那么里面的message什么时候进行分发,传递给handler的呢。下面就要讲一讲Looper了。
刚刚我们的例子是在主线程里面创建Handler的,Android默认给主线程创建了Looper对象,这个是在ActivityThread里面。
public static void main(String[] args) {
//创建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循环
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循环里面
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) {
//如果我们设置了observer,这里回调里面的messageDispatchStarting()
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
//关键是这行代码,可以看到这里调用了绑定的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这个是不是很熟悉,就是我们创建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的消息机制已经分析完毕。
另外我想扩展一点,就是ThreadLocal这个类,因为我们的looper能够跨线程通信,就是它的功劳。上面我们讲到looper调用prepare()的时候,我们新创建了一个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为空,就创建一个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();
}
}
具体算法这里就不过多阐述,总结一下就是,ThreadLocal为每一个Thread创建了一个ThreadLocalMap,里面用数组保存传进来的值,所以我们在不同的线程去取值的时候,其实我们拿到的是不同的ThreadLocalMap,里面的值也就可能不一样了,是不是比较简单?~_~