最近工作不是很忙,闲来没事去看了Handler消息的源码,在这里记录一下,别过几天又忘记了。
通过Handler可以轻松的将一个任务切换到Handler所在的线程,最常用的就是更新UI。Handler运行需要底层的MessageQueue和Looper的支撑。Handler的创建会采用当前线程的Looper来构造消息循环系统。(在主线程中创建Handler对象的时候不用创建Looper对象,在ActivityThread会被初始化,所以在主线程可以默认使用Handler)
- 先说说Looper这个类。
它在消息机制中扮演着消息循环的角色,它会不停的从MessageQueue查看是否有新消息,如果有就会立即去处理,否则一直阻塞在那里。在一个线程创建Looper,通过Looper.prepare()来创建,通过Looper,loop()来开启消息循环:
public static void prepare() {
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));//把looper对象放在ThreadLocal里面
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//创建MessageQueue
mThread = Thread.currentThread();//获取当前线程
}
可以通过prepare()在当前的线程创建一个Looper对象,在创建一个Looper对象的时候也会创建一个MessageQueue()对象。还有个创建Looper对象的方法是 prepareMainLooper(),这个方法主要是给主线程ActivityThread创建Looper对象用的,还提供一个getMainLooper()对象,这个方法是通过它可以在任何地方获取到主线程的Looper对象。最后说说ThreadLocal这个对象,创建一个ThreadLocal对象,在不同线程中用ThreadLocal.set()方法储存任何东西,在不同线程通过ThreadLocal.get()获取的类容只能是在当前线程通过ThreadLocal.set()方法存储的值。所以创建Looper对象的时候回把创建的对象放到ThreadLocal中,在后只有在当前线程才能通过get()方法获取到Looper对象,ThreadLocal的工作原理用下面代码说明:
final ThreadLocal<Boolean> mThreadLocal = new ThreadLocal<>();
mThreadLocal.set(true);
new Thread(new Runnable() {
@Override
public void run() {
Log.d("Thread1", "run: "+Thread.currentThread()+":"+mThreadLocal.get());
}
},"Thread1").start();
new Thread(new Runnable() {
@Override
public void run() {
mThreadLocal.set(true);
Log.d("Thread2", "run: "+Thread.currentThread()+":"+mThreadLocal.get());
}
},"Thread2").start();
new Thread(new Runnable() {
@Override
public void run() {
mThreadLocal.set(false);
Log.d("Thread3", "run: "+Thread.currentThread()+":"+mThreadLocal.get());
}
},"Thread3").start();
Log.d("main", "run: "+Thread.currentThread()+":"+mThreadLocal.get());
输出结果:
04-16 15:02:26.143 18435-18465/com.example.androidtext D/Thread1: run: Thread[Thread1,5,main]:null
04-16 15:02:26.143 18435-18466/com.example.androidtext D/Thread2: run: Thread[Thread2,5,main]:true
04-16 15:02:26.143 18435-18467/com.example.androidtext D/Thread3: run: Thread[Thread3,5,main]:false
04-16 15:02:26.143 18435-18435/com.example.androidtext D/main: run: Thread[main,5,main]:true
可以看出ThreadLocal的get()和set()方法所操作的对象都是当前的线程。
- 说说MessageQueue这个类。
MessageQueue这个类比较简单主要就有两个方法,一个是enqueueMessage(Message msg, long when)方法,向单链表中插入数据,next()向单链表中获取数据并删除,这个方法在Looper.loop()的方法中调用。loop()是一个死循环。 - 最后说活Handler这个类
handler主要包含了消息的发送和接收,通过post和send的一系列方法实现的
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
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;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
当调用sendMessage(Message msg)方法后,最后会调用MessageQueue的enqueueMessage()方法插入数据。在sendMessageAtTime方法中,mQueue是初始化Handler中通过Looper.myLooper()获取当前Handler的Looper对象,通过Looper.myLooper().mQueue获取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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
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();
}
}
Looper.loop()方法会不停的循环,调用MessageQueue的next()方法获取插入的数据, msg.target.dispatchMessage(msg)中的target就是绑定Looper的Handler对象,调用Handler的dispatchMessage的这个方法。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public void handleMessage(Message msg) {
}
其中首先判断callback 是否为空,其中callback 是一个Runnable对象,实际就是Handler的post方法传递的Runnable的对象。
看下来 其实Android的消息机制还是挺简单的。