Handler解析
2019-06-23 本文已影响0人
fuc_9034
Handler存在的意义
- 跟web开发的ajax有异曲同工之妙
- 使得Android开发难度大大降低(弱化了android线程间通信,根本原理是内存共享)
- 几乎看不到多线程死锁问题
消息处理流程
Handler.sendMessage()
>> Handler.enqueueMessage()
>> MessageQueue.enqueueMessage()
>> Looper.loop()
>> MessageQueue.next()
>> Handler.dispatchMessage()
>> Handler.handlerMessage()
Handler主要函数
问题
系统启动: zygote > system_server > ActivityManagerService > ActivityThread
ActivityThread类里的main()里调用了Looper.prepareMainLooper(),所以主线程已经帮我们创建好了Looper,然后继续调用Looper.loop()启动for死循环,表示只要手机启动了则主线程的Looper就已经在死循环了。为何死循环不会导致ANR呢?为什么Looper在Handler里面的初始化不是直接new?为什么Queue要在Looper里面初始化?
public Handler(Callback callback, boolean async) {
......
mLooper = Looper.myLooper();
......
mQueue = mLooper.mQueue;
......
}
Looper.prepare()
- Looper的构造函数是私有的,但是Looper并不是一个单例模式,而是在prepare()里new出looper。
- ThreadLocal是一个线程隔离工具类,
sThreadLocal.set(new Looper(quitAllowed))
就是把looper存放到当前thread的ThreadLocalMap里面,sThreadLocal.get() != null
得到的就是一个looper,如果不为空就会抛出一个异常。 - 从而保证了一个thread对应一个looper,一个looper又对应一个messageQueue,messageQueue里的message又对应一个handler (target变量)。
- 当在子线程创建handler使用getMainLooper()时,利用thread与looper一对一绑定的特点,进行线程的切换。不得不佩服Handler设计的巧妙!
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.loop()
- MessageQueue是一个具有优先级的先进先出消息队列。
- sendMessage()的时候是有一个延迟时间的,消息队列会根据延迟时间进行排序。
- 入队:
当队列满的时候,阻塞
,直到用户通过next取出消息。当next方法被调用,通知MessagQueue可以进行消息的入队。 - 出队:由Looper.loop(),启动轮询器,对queue进行轮询。当消息达到执行时间就取出来。
当message queue为空的时候,队列阻塞
,等消息队列调enqueueMessage的时候,通知队列,可以取出消息,停止阻塞。 - loop()最后会调用
msg.recycleUnchecked()
来进行消息的回收,使用的享元模式,里面会把message重置来进行再利用,而不是重新new一个message,再通过Message.obtain()重复利用,节省资源。
boolean enqueueMessage(Message msg, long when) {
//判断该消息是否有效,必须有一个target(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 可能多个线程插入消息,保证按顺序排列
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;
//如果当前队列没有消息,或者该消息需要马上执行,或者该消息,小于最前端消息
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
//是否唤醒取决于mBlocked状态
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.
//此时会先判断是否被阻塞,是否handler为空,该消息是否是异步消息
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//通过for循环来轮询消息队列
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;
}
//最后再判断是否需要唤醒
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
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层,释放当前线程,当前线程的时间片释放出去就不会出现ANR了,如果nextPollTimeoutMillis=0则执行后续方法
nativePollOnce(ptr, nextPollTimeoutMillis);
//同样保证线程安全,保证一个消息只被一个线程取出
synchronized (this) {
//找到当前的时间
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
//获取消息队列头部消息
Message msg = mMessages;
if (msg != null && msg.target == null) {
//一直向后寻找,直到碰到一个异步消息,跳出 while 循环
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 如果执行时间没到,消息执行需要等待的时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//获取了一条可执行的消息,此时阻塞需要改为 false
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 {
// 没有消息了,下次循环进入等待
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)) {
//mIdleHandlers消息队列为空时的额外处理集合
pendingIdleHandlerCount = mIdleHandlers.size();
}
//跳出当次循环很重要
if (pendingIdleHandlerCount <= 0) {
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;
}
}