一、Handler机制概述
Handler机制也可以说是消息机制,Handler的运行时需要MessageQueue和Lopper的支持的。MessageQueue指消息队列,用来存储Message,虽然名为队列但其实是单向链表结构;Lopper用于消息循环,采用死循环的方式,如果有需要处理的消息就会处理,否则就会阻塞等待。
Handler的工作原理如下:
Handler发送一个消息,调用MessageQueue的enqueueMessage方法将Message加入消息队列;Lopper通过loop方法取出消息,最后转发给Handler,最终在handlerMessage中处理。
二、源码分析
2.1Handler构造方法
Handler的构造方法,有很多,但是最后都是调用两个方法,分别是Handler(Callback callback, boolean async)和Handler(Looper looper, Callback callback, boolean async)
public Handler(Callback callback, boolean async) {
//当设置为true时检测匿名,本地或者成员类继承Handler并且不是静态,这种类型的类会造成潜在的内存泄漏
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());
}
}
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;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
2.2 创建以及存储Looper
我们可以从Handler的构造方法中发现Looper是创建的必要参数之一,那么创建Handler之前那就要先创建Looper,那么Looper是如何来的,我们可以看到,一种是将Looper实例化通过构造穿进来,另一种是Looper.myLooper()直接获取的
- 自己创建一个Looper
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));
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
可以看到创建Looper有两种方式,一种是Looper.prepare(),一种是Looper. prepareMainLooper(),第二种是给应用主线程创建Looper的,所以我们自己创建使用第一种。我们继续看会发现Looper创建后会存放在ThreadLocal中,我们来看一下这个ThreadLocal是如何存储Looper的,看源码:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
看到这个是不是很熟悉的东西:key、value,key是当前线程,value就是当前线程对应的Looper,创建的时候还会通过ThreadLocal.get() 获取当前线程的Looper判断是否已经创建过Looper,所以可以知道Looper是跟线程绑定的,一个线程只会有一个Looper不可重复创建,ThreadLocal是来存储这些Looper的,key就是Looper所在的线程。
- Looper.myLooper()
我们再来看看Looper.myLooper()的源码
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
可以看到是从ThreadLocal获取存储的Looper,再看ThreadLocal.get()源码:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
就是返回当前线程所对应的Looper
所以我们可以知道,在Handler创建前我们需要通过Looper.prepare()创建出当前线程自己的Looper,主线程则不需要创建,因为系统已经创建了,这个后面介绍。
2.3消息发送
那么Looper有了,Handler创建了,是如何发送消息的呢。我们可以发现发送消息有下面几种方法:
- 1.sendMessage(Message msg)
- 2.sendEmptyMessage(int what)
- 3.sendEmptyMessageDelayed(int what, long delayMillis)
- 4.sendEmptyMessageAtTime(int what, long uptimeMillis)
- 5.sendMessageDelayed(Message msg, long delayMillis)
- 6.sendMessageAtTime(Message msg, long uptimeMillis)
- 7.sendMessageAtFrontOfQueue(Message msg)
这里1,2,3,4,5最后调用的都是6。这里需要注意一个地方,就是系统是如何计算MessageDelayed的延迟时间的,我们看一下源码:
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
可以看到是用SystemClock.uptimeMillis() + delayMillis,那么这个SystemClock.uptimeMillis()又是什么,源码也有:
/**
* Returns milliseconds since boot, not counting time spent in deep sleep.
*
* @return milliseconds of non-sleep uptime since boot.
*/
@CriticalNative
native public static long uptimeMillis();
大概意思返回自启动以来的毫秒数,不计算深度睡眠所花费的时间。注意了这里不是是用的手机当前时间。
2.4消息加入消息队列
消息发送了,这些消息是怎么管理的,那就是通过消息队列MessageQueue,把这些消息加入到消息队列中去。这个消息队列虽然名为队列却是单向链表。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
接着看MessageQueue的enqueueMessage方法
boolean enqueueMessage(Message msg, long when) {
//handler为空抛异常
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//消息已经在队列中抛异常
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;
//当前队列的第一个msg
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
//当没有头消息或者加入消息的触发事件为0或者早于头消息的话就讲加入消息放在队头
// 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;
}
至此,入队列完全结束。从这里可以看出,延迟低的消息会被加到延迟高的消息之前。
2.5消息处理
消息进入消息队列后就需要Lopper对消息进行提取,使用Looper.loop()方法不断的从消息队列中取出消息。这个方法是需要手动调用的,activity除外,因为activity中系统已经帮我们调用了。这个我们后面再看,下面我们看看Looper.loop()的部分源码:
public static void loop() {
......
for (;;) {
//拿到队头的消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
try {
//msg.target.dispatchMessage(msg)其实就是Handler.dispatchMessage(msg);
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......
}
}
这里loop是一个无限循环的操作,queue.next()拿到消息然后发送给handler,那如果拿到是的是延迟消息怎么办,我们来看看queue.next()源码:
Message next() {
......
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
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) {
//当前系统自启动来的未休眠时间小于消息出发时间是不会返回msg的
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.
//到了消息触发事件,返回msg
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// 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.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
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 {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
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;
}
}
也就是只有到了消息触发的时间调用next才会返回msg。至此全部结束。这里面还有一个知识点,就是IdleHandler,这个我们等下讲。
三、现在来讲讲上面遗留的问题
- 为什么Activity中使用Handler不需要我们创建Looper
- 为什么Activity中使用Handler不需要我们自己调用Looper.loop()去循环获取消息
- Looper.loop()是个无限循环,且会阻塞线程,那么主线程为什么看起来没有阻塞呢
我们来看一下源码:
public static void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
......
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
可以看到在ActivityThread中Looper.prepareMainLooper()创建的就是主线程中的Looper,这里是系统自己创建好的;随后创建了MainThreadHandler,主线程中自己的Handler;再然后调用了Looper.loop()。这里一、二两个问题就知道答案了,第三个问题的关键就在这个MainThreadHandler,系统就是使用这个MainThreadHandler去处理接收到的消息的,所以主线程看起来就没有被阻塞。我们来看一下MainThreadHandler是通过thread.getHandler()方法获取的,我们看一下这个方法:
final Handler getHandler() {
return mH;
}
我们再看一下mH怎么来的:
final H mH = new H();
继续:
class H extends Handler {
......
public static final int GC_WHEN_IDLE = 120;
public static final int RELAUNCH_ACTIVITY = 160;
......
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
case BIND_APPLICATION: return "BIND_APPLICATION";
......
}
}
return Integer.toString(code);
}
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
......
case GC_WHEN_IDLE:
scheduleGcIdler();
break;
......
case RELAUNCH_ACTIVITY:
handleRelaunchActivityLocally((IBinder) msg.obj);
break;
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
((SomeArgs) obj).recycle();
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
}
主线程会使用这个mH来处理消息。
我们在这里也可以看到之前在Loop.loop()方法中看到的IdleHandler,这里举例用scheduleGcIdler()方法
四、IdleHandler是什么
我们来跟一下scheduleGcIdler()源码:
void scheduleGcIdler() {
if (!mGcIdlerScheduled) {
mGcIdlerScheduled = true;
Looper.myQueue().addIdleHandler(mGcIdler);
}
mH.removeMessages(H.GC_WHEN_IDLE);
}
我们可以看到Looper.myQueue().addIdleHandler加入了一个mGcIdler,我们来看一下这个mGcIdler:
final class GcIdler implements MessageQueue.IdleHandler {
@Override
public final boolean queueIdle() {
doGcIfNeeded();
return false;
}
}
我们发现IdleHandler原来是一个接口:
public static interface IdleHandler {
/**
* Called when the message queue has run out of messages and will now
* wait for more. Return true to keep your idle handler active, false
* to have it removed. This may be called if there are still messages
* pending in the queue, but they are all scheduled to be dispatched
* after the current time.
*/
boolean queueIdle();
}
这个queueIdle()方法表示在消息队列中消息用完后立即调用,如果返回true则会保持在系统空闲时不断调用,false则只调用一次就被删除。如果消息队列中有消息,就会被挂起等待消息处理。我们现在在来看看MessageQueue.next()方法:
Message next() {
....
for (;;) {
......
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.
......
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
......
}
// 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 {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
......
}
}
可以在这里看到IdleHandler执行过程确实如此。
五、补充知识点
5.1HandlerThread是什么
我们通过观察源码可以发现HandlerThread继承自Thread所以他拥有Thread能力,与之不同的是HandlerThread内部自建创建了一个Handler,提供了Looper。
5.2Message.obtain()
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();
}
从消息池中返回新的消息,且不会分配新对象,避免了消息对象的重复创建跟销毁。
5.3怎么维护消息池
消息池也是链表结构,在消息被消费后消息池会执行回收操作,将该消息内部数据清空然后添加消息链表最前面。