前言
首先介绍一下Handler和Looper,MessageQueue分别是做什么的,有什么用!
- Handler:线程间发送与处理消息
- Looper:管理MessageQueue消息队列,循环读取MessageQueue中的消息
- MessageQueue:消息队列
- Message:消息的载体
首先我们如果在主线程使用Handler的话,肯定是下面的步骤:
handler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("test","Handler消息!");
}
};
为什么没有调用Looper的方法呢?
因为主线程已经默认给我们调用了Looper的这个两方法
Looper.prepare();
Looper.loop();
现在我们开始一步一步的分析
- 先从Looper的prepare和loop两个方法开始:
prepare方法:
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是否为空,如果为空就创建一个新的Looper对象,不为空的话就会抛出异常
这就是为什么在一个线程Looper不能调用两次preare()方法的原因
代码中把Looper对象存到了sThreadLocal中,这个sThreadLocal又是什么呢?
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
简单分析下ThreadLocal:
ThreadLocal内部有个ThreadLocalMap类用来存储值的,这个ThreadLocalMap使用键值对进行存储的,在Thread类中有个ThreadLocalMap实例对象,也就是说在每个线程都有一个ThreadLocalMap对象
ThreadLocal存取值方法
ThreadLocal.get方法:
- ThreadLocal会获取当前Thread的ThreadLocalMap对象然后取出值
TrheadLocal.set方法 - ThreadLocal会获取当前Thread的ThreadLocalMap对象然后存入值
假如我们调用Looper的myLooper()方法获取当前Thread的Looper,ThreadLocal就会获取当前Thread来取出当前Thread的ThreadLocalMap对象,然后取出里面的Looper对象
个人觉得ThreadLocal就是可以为各个线程存储其对应的数据
贴出ThreadLocal部分代码:
public T get() {
// 获取当前线程
Thread t = Thread.currentThread();
// 取出当前线程的ThreadLocalMap对象
ThreadLocalMap map = getMap(t);
// 判断如果map不为空就取出对应的值
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
public void set(T value) {
// 获取当前线程
Thread t = Thread.currentThread();
// 取出当前线程的ThreadLocalMap对象
ThreadLocalMap map = getMap(t);
// 判断如果map为空则进行创建
// 不为空就进行存值
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
// 获取线程中的threadLocals对象
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
Ok,现在看loop方法
我在代码比较重要的地方注释进行解释
public static void loop() {
// 获取了当前Thread的Looper对象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 获取当前Looper的MessageQueue
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(;;){}这种写法就是无限循环的意思
for (;;) {
// 获取MessageQueue中的Message对象
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));
}
// 我们看这里
// 这里才是关键的地方
// 调用Message.target对象的dispatchMessage方法,target其实就是Handler的引用;
// 而Handler的dispatchMessage方法内部又调用了handleMessage方法去处理
// 而我们每次创建Handler都会实现handlerMessage方法,是不是有点明白什么了.
// OK这个我们待会详细再将
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();
}
}
现在可以看出来,loop方法内部就是开启了一个死循环,不断的从MessageQueue中取出Message进行处理,
通过Message.target.dispatchMessage发送Handler所在的线程取处理
Looper的preare和loop方法分析好了,现在我们开始从sendMessage方法一直往下分析,看下Handler从发送到处理到底经过了哪些流程
关于Handler发送Message有两种发送方式
简单说下区别:
// 1 每次都会新建Message对象
Message message = new Message();
message.what = 0;
handler.sendMessage(message);
// 2 会从Message消息池中取出已存在的Message对象进行复用
handler.obtainMessage(0).sendToTarget();
// 因为obtainMessage会取出已存在的Message对象进行复用,所以个人建议使用obtainMessage
好的,方便我们的理解,我们就用sendMessage开始分析,
下面是sendMessage调用过程
public final boolean sendMessage(Message msg)
{
// sendMessage方法延时时间为0,就是不延时处理
return sendMessageDelayed(msg, 0);
}
// delayMillis延时时间
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
// SystemClock.uptimeMillis() // 从开机到现在的毫秒数(手机睡眠的时间不包括在内)
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) {
// 设置当前消息的目标handler
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
我们调用sendMessage方法发送消息,sendMessage方法最终会走到enqueueMessage方法中,在enqueueMessage方法中,将message的target对象设置为当前handler对象
刚才我们在loop方法中是不是看到使用了message.target对象,原来target是在这里赋值的
然后看方法内部最后调用了queue.equeueMessage方法,也就是说调用了MessageQueue对象的enqueueMessage方法
我们跟着这个方法进入看看
boolean enqueueMessage(Message msg, long when) {
// 如果msg.target为空抛出异常
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
// 如果msg正在处理中抛出异常
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
// 停止
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;
// 如果p == null || when == 0 || when < p.when,则将此次消息插入消息队列头部
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
// 将msg的下一个位置设置成当前头部的消息
msg.next = p;
// 再将msg赋值为mMessages
// 就完成了当前消息插入消息队列头部的操作
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;
}
关于enqueueMessage内部主要进行消息的插入队列中
如果p == null || when == 0 || when < p.when则将该条消息插入队列的头部
(个人理解,p ==null 可能就是第一次插入消息时,when < p.when的时候就是后面插入的消息要比头部的消息先执行,所以插入到头部,先执行意思就是延时时间要比头部的短)
否则就把消息插入队列的尾部,或者插入延时消息比自己时间要长的前一个位置
关于插入延时消息比自己时间要长的前一个位置的解释:
比如现在连续发送两个消息,第一个消息延时1分钟处于消息池中最后一个位置,第二个消息延时3秒的,此时第一个消息会被插入到延时1分钟消息的前面
Ok此时消息已经被插入消息队列,那么还记得刚才的loop方法吗,因为是无限循环方法,所以被插入到队列的消息会被Looper对象取出并处理
看代码:
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
在loop方法中如果取到message就会调用它的target对象.dispatchMessage方法,刚才已经说了target就是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);
}
}
public void handleMessage(Message msg) {
}
我们先分析msg.callback和mCallback.handleMessage方法,最后再说handleMessage(msg)方法
关于msg.callback和mCallback.handleMessage方法
msg.callback是通过Message对象设置的一个Runnable实现对象,当前消息发送之后会出发该实现方法
关于调用的handleCallback只是竹筏msg.callback的run方法
private static void handleCallback(Message message) {
message.callback.run();
}
关于会走msg.callback的写法
Message m = Message.obtain(handler, new Runnable() {
@Override
public void run() {
}
});
m.sendToTarget();
mCallback.handleMessage可以看下面的代码就会明白
handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
return false;
}
});
mCallback是通过构造传入的一个接口,而这个接口中有个方法也是handleMessage(msg)方法
看代码:
Handler内部的CallBack接口
···
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
···
最后说我们重写的handleMessage方法
如果我们没有使用以上两种方式,而是使用重写handleMessage方法,
也就是这种:
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
那么在dispatchMessage中就会走到else的最后面调用了handlerMessage(msg)方法,而我们又实现了handleMessage方法,
所以消息会在handleMessage方法中处理掉;