【Android】Handler、Looper、消息队列运行机制原理解析及相关面试题

public static void loop() {

final Looper me = myLooper();

final MessageQueue queue = me.mQueue;

for (;😉 {

Message msg = queue.next(); // might block

try {

msg.target.dispatchMessage(msg);

} // …

}

}

可以发现,loop()函数其实是一个死循环;在这个循环中,不停地从消息队列中取下一条消息,然后分发给对应的Handler(msg.target)进行处理。 “Looper”就是循环的意思,这正对应了loop()方法中的这个死循环。在这个死循环里面,可以无限读取消息队列中的消息。使用quit()方法可以退出这个循环;如果在主线程的Looper退出,也就意味着程序的结束——将会得到 java.lang.IllegalStateException: Main thread not allowed to quit. 的报错信息。

1.2 消息队列 - MessageQueue

  • Message

Message消息是Handler传递信息的基本单位。在Handler中,不管是调用post(Runnable)还是sendMessage(Message)还是其他的什么,最终都会构建一个Message对象,并添加到消息队列mQueue中。Message中保存了消息的类型、参数、对应的Handler等一些少量的数据。

1.1中说到,Looper.loop()会发起一个死循环,在消息队列中不停取值。那么,为什么这里不会卡死呢?

Looper#loop()

public static void loop() {

final Looper me = myLooper();

final MessageQueue queue = me.mQueue;

for (;😉 {

Message msg = queue.next(); // might block

try {

msg.target.dispatchMessage(msg);

} // …

}

}

跳转到MessageQueue.next(),看一下消息队列是怎么取下一条消息的。这里删去了大部分代码,只剩下核心的部分,方便梳理流程:

Message next() {

int nextPollTimeoutMillis = 0;

for (;😉 {

nativePollOnce(ptr, nextPollTimeoutMillis); // 会阻塞线程直到下一个消息到来

synchronized (this) {

final long now = SystemClock.uptimeMillis();

Message msg = mMessages;

if (msg != null) {

if (now < msg.when) { // 时候未到

nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);

} else {

mMessages = msg.next;

msg.next = null;

msg.markInUse();

return msg;

}

}

}

}

}

nativePollOnce是一个本地方法,它会阻塞线程直到下一个有消息来临。这类似于Java中的DelayQueue,不同点是DelayQueue是通过优先队列+锁实现的。 在MessageQueue中有一个Message类型的对象mMessage,它保存着消息队列中最早的一条消息。当阻塞的线程被唤醒时,next()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值