Handler是大家使用非常多的一个android组件,通过使用handler,可以在子线程和主线程间方便的切换,使工作线程在后台做完事情之后,会返回到主线程,然后我们可以做些类似更新UI之类的需要在主线程中做的事情,下面我们来看下具体handler的源码,来对handler的内部运行机制有个清晰的了解。
我们先来看看,一般我们怎么使用handler的,通过有2种使用方法,如下:
```java
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
switch (msg.what){
//1处
}
return false;
}
});
new Thread(new Runnable() {
@Override
public void run() {
Message message = Message.obtain();
message.what = 1;
message.obj = new Object();
//方法1
handler.sendMessage(message);
//方法2
handler.post(new Runnable() {
@Override
public void run() {
//TODO
}
});
}
}).start();
```
以上方法1和方法2就是一般的2种用法,其实本质都是一样,最后都是调用到一个地方,下面我们就从Handler创建开始说起。
Handler的创建
Handler的创建简单的直接new Handler()就可以了,源码如下:
```java
public Handler(@Nullable 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());
}
}
// 1处
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
```
从begin这里看到,在初始化的时候,会有一个判断,mLooper是否为空,mLooper是从Looper.myLooper中来的,我们进入这个方法
```java
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
```
可以看到,sThreadLocal是一个static final的变量,说明Looper只会有一个这个变量,而且不会变,它返回一个Looper,我们在跟进去看get()的具体代码,
```java
public T get() {
Thread t = Thread.currentThread(); //拿到当前线程
ThreadLocalMap map = getMap(t); //获取当前线程的ThreadLocalMap
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //获取ThreadLocalMap的Entry
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result; //返回Entry的value,这里即是当前线程的Looper
}
}
return setInitialValue();//以上没有返回值,则创建
}
```
再回到之前Handler初始化地方,如果mLooper为空的话,就是看到经常看到的错误 "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()",一般我们在子线程中没有创建Loop的话都会有这个错误,而主线程中为什么不会报这个错误呢,这是因为在activiy初始化的时候,已经默认创建了一个Looper,在ActiviyThread中的main方法里有Looper.prepareMainLooper(),我们跟进去看
```java
public static void prepareMainLooper() {
prepare(false); // 1处
synchronized (Looper.class) {
if (sMainLooper != null) { // 2处
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper(); //3,此处myLooper()可能为null?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));
}
```
可以看到在1处调用了prepare方法,prepare方法就是创建当前线程的Looper过程,如果已经有了Looper,则会抛出错误,由此可知每个线程只有一个Looper,如果Looper是空的话,则会创建一个Looper,我们看下Looper初始化的代码,
```java
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
```
可以看到每初始化一个Looper会创建一个MessageQueue,由于每个线程只有一个Looper,所以Looper只会创建一次,MessageQueue也就只有一个,在回到前面的代码2处,此时如果主线程的sMainLooper非空,则会报错,因为一个线程只能有一个Looper,如果sMainLooper是空的,则把刚才prepare()方法中创建的Looper给它。至此Handler初始化完成,此时Handler中必要的Looper和MessageQueue都已经创建完成,后面会在说到这2个重要的部件。
下面让我们再来看下Handler发送的过程,前面说到Handler的2种方式,post和sendMessage其实是同一种方式,我们可以看下post的源码:
```java
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
```
可以看到最后都调到了sendMessageDelayed,然后一路跟进去,最后会走到Handler的enqueueMessage方法
```java
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);
}
```
之后再会走到MessageQueue的enqueueMessage方法,此处的queue,即从当前线程的Looper中取出的MessageQueue,然后我们重点看下MessageQueue的enqueueMessage方法:
## enqueueMessage入队
```java
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是当前新的消息
msg.when = when;
Message p = mMessages;//mMessages是当前头节点消息,即p也是头节点
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.
//此处如果当前是阻塞的(mBlocked ),同时头部节点是同步屏障(p.target == null),传入的消息是个异步消息(msg.isAsynchronous())
//那么就需要唤醒
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//下面的for循环就是寻找p的插入点
for (;;) {
prev = p;
p = p.next;
//此处p为当前循环到的消息,并且从第二个开始,因为当前需要插入的点肯定在第一个后面,否则就不会进入else循环
if (p == null || when < p.when) {
//如果需要插入的点在p前面,则跳出循环
break;
}
//如果needWake是true,并且p是个异步消息,同时插入点肯定在p后面,那说明msg不是第一个异步消息,所以没必要唤醒
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;
}
```
## loop方法
上面代码的注释里都写了具体的过程,这里就是插入的过程,既然有入队,那么也有出队,下面再看下出队的情况。还记得用Handler的时候需要在prepare方法中创建Handler,然后还要调用Looper.loop这个方法吗,loop这个方法就是开启接收消息的地方,方法内容比较多,看下主要的地方
```java
public static void loop() {
.....省略
for (;;) {
Message msg = queue.next(); // might block //此处 1
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);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
msg.target.dispatchMessage(msg);// 此处2
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);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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();//此处3 为回收msg
}
}
```
## next()方法
通过代码我们可以看到,loop方法会开启一个死循环,然后在1处从Message队列中取出消息,2处我们就比较熟悉了,就是会回调到Handler注册的那个回调方法中,3处回收处理完的msg。先看1处,此处是MessageQueue的next方法,我们看下此处代码:
```java
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//这个方法是native层的阻塞方法,个人简单理解为java中的wait,第二个参数就是阻塞的时间,-1为阻塞,0为不阻塞,正数为阻塞一段时间后唤醒,
回想下上面我们讨论的enqueueMessage方法,最后有nativeWake这个方法,就是唤醒用的,同样可以理解为java中的notify,唤醒的就是此处的阻塞
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
// 当前头结点
Message msg = mMessages;
//如果头结点是屏障消息,那么就进入循环找到第一条异步消息
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
// 计算出需要阻塞多少时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
//此分支msg是一个异步消息,由于这个异步消息要返回,下面这句话把msg前面消息指向msg后面的消息
prevMsg.next = msg.next;
} else {
//此分支不是异步消息,把队头消息指向msg的后面
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
//因为msg为空,所以阻塞,此时,loop方法会阻塞
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
//下面是IdleHandler,这种Handler可以理解为是一种在没有消息的时候,处理的消息,感觉可以做些不太紧急,不太重要的事情
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
//第一次循环pendingIdleHandlerCount为-1,如果队头消息是空,或者对头消息没有到执行的时间,则会开始idleHandler的执行
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
//计算出idleHandler的数量
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
//如果第一次上面那个if没进去,pendingIdleHandlerCount还是-1,则阻塞,如果进去了,且为0,同样阻塞,大于0,则执行下面的方法
//如果不是第一次,则肯定>=0,只有为0的时候才会阻塞,否则执行下面的方法
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
//把mIdleHandlers集合转变为数组,开始下面的执行循环
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
//执行idleHandler,返回值true表示不会从mIdleHandlers中删除此idleHandler,下次队列为空值,改idleHandler会再次执行,false则只执
行一次后从队列中删除
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
//根据keep来决定,是否删除该idleHandler
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
```
## dispatchMessage方法
以上就是队列取数据的过程,回到上面loop方法的2处,msg.target.dispatchMessage(msg),这里的targt就是handler,然后看下dispatchMessage方法:
```java
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) { //1处
handleCallback(msg);
} else {
if (mCallback != null) { //2处
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
```
先看1处,此处判断Message的callback是否为空,如果为空,就会回调它,一般这个msg的回调,是我们调用handler.post(new Runnable().....)中传入的。接着就是else里面,此处的mCallback一般是通过Handler handler = new Handler(callBack)中的callback,该方法提供了一个快速回调的接口,省的我们按照常规的去继承一个Handler后通过重写它的回调函数来写了,注意这个callback有一个boolean的返回值,如果返回是true的话,就不会再执行Handler的handleMessage方法了,这点需要注意。
## recycleUnchecked方法
在dispatchMessage后,我们再来看下Message的recycleUnchecked()方法,
```java
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool; //sPool是表头,该行把当前表头赋值给next
sPool = this; //把当前message放到表头
sPoolSize++; //总数加1
}
}
}
```
该方法首先会把flags赋值为FLAG_IN_USE,当回收和入队(也就是上面MessageQueue中的enqueueMessage方法)时,都会把flags赋值为FLAG_IN_USE,而再每次obtain一个message的时候,会flags会是0,所以我们再回去看下enqueueMessage方法,开始会有msg.isInUse()判断,如果是true则抛出异常,否则会把flags置为FLAG_IN_USE,下面就是是一系列的置0操作,最后synchronized中,如果当前消息池中的数量小于MAX_POOL_SIZE(50),则会把该回收消息放入表头,否则就不操作,说明最多会缓存50个消息。
好了,以上是关于Handler的主要流程部分,由于篇幅比较大了,后面的内容会放到第二部分再聊。
Handler源码解析