Handler/Looper/MessageQueue 深度解析(原理 + 场景 + 面试题)
1. Handler 延时消息原理详解
场景:延时消息与定时任务
延时消息底层原理
public class MessageQueue {
private Message mMessages; // 消息链表头
private boolean mQuit = false;
Message next() {
for (;;) {
if (mQuit) return null;
long nextPollTimeoutMillis = 0;
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 遇到同步屏障,查找异步消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// 消息时间未到,计算等待时间
nextPollTimeoutMillis = msg.when - now;
} else {
// 消息时间到了,返回消息
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
return msg;
}
}
}
// 关键:使用 epoll 机制等待
nativePollOnce(ptr, nextPollTimeoutMillis);
}
}
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// 插入到链表头部
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// 按时间顺序插入到链表中间
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;
prev.next = msg;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
}
为什么不会阻塞主线程?
-
epoll 机制:nativePollOnce() 使用 Linux epoll 机制,当没有消息时线程会进入等待状态,不占用 CPU
-
时间计算:根据下一条消息的时间计算等待时长
-
唤醒机制:有新消息时通过 nativeWake() 唤醒线程
面试题:延时消息的精确性
- 问题:Handler 的延时消息是否精确?
- 答案:不精确,原因:
- 消息按时间排序,但处理有延迟
- 主线程繁忙时,消息处理会延迟
- 系统休眠时,时间计算可能不准确
2. 消息屏障与异步消息
场景:VSync 信号处理
private val handler = Handler(Looper.getMainLooper())
private val asyncHandler = Handler(Looper.getMainLooper()) { msg ->
Log.d("Barrier", "异步消息处理: ${msg.what}")
true
}
fun demonstrateBarrier() {
Log.d("Barrier", "开始演示消息屏障")
// 1. 插入同步屏障
val token = handler.postSyncBarrier()
Log.d("Barrier", "插入同步屏障")
// 2. 普通消息被阻塞
handler.post {
Log.d("Barrier", "普通消息1 - 被阻塞")
}
handler.post {
Log.d("Barrier", "普通消息2 - 被阻塞")
}
// 3. 异步消息可以越过屏障
val asyncMsg1 = Message.obtain(asyncHandler, 1)
asyncMsg1.isAsynchronous = true
handler.sendMessage(asyncMsg1)
val asyncMsg2 = Message.obtain(asyncHandler, 2)
asyncMsg2.isAsynchronous = true
handler.sendMessage(asyncMsg2)
// 4. 移除屏障
handler.removeCallbacksAndMessages(token)
Log.d("Barrier", "移除同步屏障,普通消息开始处理")
}
}
// VSync 信号处理模拟
class VSyncHandler {
private val handler = Handler(Looper.getMainLooper())
private var vsyncToken: Any? = null
fun onVSync() {
// VSync 信号到达时插入屏障
vsyncToken = handler.postSyncBarrier()
// 发送异步消息处理帧渲染
val frameMsg = Message.obtain(handler) {
Log.d("VSync", "处理帧渲染")
// 执行 onDraw 等渲染逻辑
}
frameMsg.isAsynchronous = true
handler.sendMessageAtFrontOfQueue(frameMsg)
// 移除屏障
handler.removeCallbacksAndMessages(vsyncToken)
}
}
消息屏障原理
Message next() {
for (;;) {
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// 遇到同步屏障(target == null)
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
// 只处理异步消息,跳过普通消息
}
if (msg != null) {
if (now < msg.when) {
// 等待
} else {
// 返回消息
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
return msg;
}
}
}
}
}
异步消息使用场景
- VSync 信号:确保帧渲染优先处理
- 输入事件:触摸、按键事件需要及时响应
- 系统消息:系统级的高优先级消息
面试题:为什么异步消息优先级更高?
- 答案:在同步屏障存在时,只有异步消息能被处理,普通消息被阻塞
- 应用场景:VSync 信号、输入事件、系统消息
- 实现原理:通过 msg.isAsynchronous() 标记,在屏障时跳过普通消息
3. 主线程 Looper 创建
场景:主线程初始化
fun demonstrateMainLooper() {
Log.d("Looper", "主线程: ${Thread.currentThread().name}")
Log.d("Looper", "主线程 Looper: ${Looper.myLooper()}")
Log.d("Looper", "主线程 MessageQueue: ${Looper.myLooper()?.queue}")
}
}
// ActivityThread.java 中的主线程初始化
class ActivityThread {
public static void main(String[] args) {
// 1. 准备主线程 Looper
Looper.prepareMainLooper();
// 2. 创建 ActivityThread
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 3. 开始消息循环
Looper.loop();
}
}
// Looper.java 简化版
class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepareMainLooper() {
prepare(false); // 主线程不允许退出
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("主线程 Looper 已创建");
}
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("每个线程只能有一个 Looper");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public static Looper myLooper() {
return sThreadLocal.get();
}
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("没有调用 prepare()");
}
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // 可能阻塞
if (msg == null) {
return;
}
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
}
}
}
ThreadLocal 原理
// 每个线程都有独立的 ThreadLocalMap
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
createMap(t, value);
}
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
return (T) e.value;
}
}
return setInitialValue();
}
}
// ThreadLocalMap 数据结构
class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
private int size = 0;
private static final int INITIAL_CAPACITY = 16;
}
面试题:为什么主线程不用创建 Looper?
- 答案:在 ActivityThread.main() 中已经调用了 Looper.prepareMainLooper()
- 时机:应用启动时,在 Activity 创建之前
- 特点:主线程 Looper 不允许退出(quitAllowed = false)
4. IdleHandler 与低优先级任务
场景:空闲时执行任务
private val handler = Handler(Looper.getMainLooper())
fun demonstrateIdleHandler() {
Log.d("IdleHandler", "开始演示")
// 添加 IdleHandler
Looper.myLooper()?.queue?.addIdleHandler(object : MessageQueue.IdleHandler {
override fun queueIdle(): Boolean {
Log.d("IdleHandler", "主线程空闲,执行低优先级任务")
// 执行一些不紧急的任务
performLowPriorityTask()
return false // 移除这个 IdleHandler
}
})
// 添加持续性的 IdleHandler
Looper.myLooper()?.queue?.addIdleHandler(object : MessageQueue.IdleHandler {
override fun queueIdle(): Boolean {
Log.d("IdleHandler", "定期检查任务")
checkPeriodicTask()
return true // 保留,下次空闲时继续执行
}
})
// 模拟一些任务
repeat(5) { i ->
handler.post {
Log.d("IdleHandler", "执行任务 $i")
Thread.sleep(100) // 模拟耗时
}
}
}
private fun performLowPriorityTask() {
// 预加载数据
preloadData()
// 清理缓存
cleanCache()
// 统计信息
collectStats()
}
private fun checkPeriodicTask() {
// 检查网络状态
checkNetworkStatus()
// 检查更新
checkForUpdates()
}
}
// 启动优化中的 IdleHandler 使用
class StartupOptimizer {
fun optimizeStartup() {
// 关键初始化
initCriticalComponents()
// 非关键初始化延迟到空闲时
Looper.myLooper()?.queue?.addIdleHandler(object : MessageQueue.IdleHandler {
override fun queueIdle(): Boolean {
Log.d("Startup", "主线程空闲,执行非关键初始化")
// 预加载一些数据
preloadUserData()
// 初始化一些服务
initNonCriticalServices()
// 预热一些组件
warmupComponents()
return false // 只执行一次
}
})
}
}
IdleHandler 原理
Message next() {
for (;;) {
synchronized (this) {
// ... 消息处理逻辑
if (msg != null) {
// 有消息,处理消息
return msg;
}
}
// 没有消息时,处理 IdleHandler
if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 没有 IdleHandler,继续等待
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = mIdleHandlers.toArray(new IdleHandler[mIdleHandlers.size()]);
}
// 执行 IdleHandler
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null;
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("IdleHandler", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
面试题:IdleHandler 的使用场景
- 启动优化:非关键初始化延迟到空闲时
- 预加载:空闲时预加载数据
- 清理任务:定期清理缓存、统计信息
- 监控任务:检查网络状态、更新等
5. IntentService 与后台任务
场景:后台任务处理
override fun onHandleIntent(intent: Intent?) {
Log.d("IntentService", "开始处理任务: ${intent?.action}")
when (intent?.action) {
"UPLOAD_FILE" -> {
val filePath = intent.getStringExtra("file_path")
uploadFile(filePath)
}
"SYNC_DATA" -> {
syncData()
}
"CLEAN_CACHE" -> {
cleanCache()
}
}
Log.d("IntentService", "任务处理完成")
}
private fun uploadFile(filePath: String?) {
// 模拟文件上传
Thread.sleep(5000)
Log.d("IntentService", "文件上传完成: $filePath")
}
private fun syncData() {
// 模拟数据同步
Thread.sleep(3000)
Log.d("IntentService", "数据同步完成")
}
private fun cleanCache() {
// 模拟清理缓存
Thread.sleep(2000)
Log.d("IntentService", "缓存清理完成")
}
}
// 使用 IntentService
class ServiceExample {
fun startBackgroundTask() {
val intent = Intent(context, MyIntentService::class.java).apply {
action = "UPLOAD_FILE"
putExtra("file_path", "/path/to/file")
}
startService(intent)
}
}
IntentService 原理
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent) msg.obj);
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
protected abstract void onHandleIntent(Intent intent);
}
HandlerThread 原理
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
}
面试题:IntentService 的特点
- 单线程:使用 HandlerThread 确保单线程处理
- 自动停止:任务完成后自动调用 stopSelf()
- 队列处理:按顺序处理 Intent
- 后台执行:不阻塞主线程
6. Handler 解决的实际问题
场景:线程间通信
private val mainHandler = Handler(Looper.getMainLooper())
private val backgroundHandler = Handler(Looper.getMainLooper())
fun demonstrateCommunication() {
Log.d("Communication", "主线程开始")
// 后台线程执行任务
Thread {
Log.d("Communication", "后台线程开始工作")
// 模拟耗时操作
Thread.sleep(2000)
// 回到主线程更新 UI
mainHandler.post {
Log.d("Communication", "回到主线程更新 UI")
updateUI()
}
// 发送消息
val msg = Message.obtain(mainHandler, 1)
msg.obj = "任务完成"
mainHandler.sendMessage(msg)
}.start()
}
private fun updateUI() {
// 更新 UI 组件
}
}
// 定时任务
class TimerExample {
private val handler = Handler(Looper.getMainLooper())
private val runnable = object : Runnable {
override fun run() {
Log.d("Timer", "定时任务执行: ${System.currentTimeMillis()}")
handler.postDelayed(this, 1000) // 继续下一次
}
}
fun startTimer() {
handler.post(runnable)
}
fun stopTimer() {
handler.removeCallbacks(runnable)
}
}
// 延迟执行
class DelayExample {
private val handler = Handler(Looper.getMainLooper())
fun delayExecute() {
Log.d("Delay", "开始延迟执行")
handler.postDelayed({
Log.d("Delay", "5秒后执行")
}, 5000)
}
}
Handler 解决的问题
- 线程间通信:后台线程 → 主线程更新 UI
- 定时任务:定期执行某些操作
- 延迟执行:延迟执行任务
- 消息队列:有序处理消息
- 异步处理:不阻塞主线程
7. 衍生面试题
1. Handler 内存泄漏
// 错误示例:匿名内部类持有外部引用
private val handler = Handler(Looper.getMainLooper())
fun wrongWay() {
handler.postDelayed({
// 这个 lambda 隐式持有 Activity 引用
updateUI() // 可能导致泄漏
}, 10000)
}
// 正确示例:使用静态内部类
private val handler = Handler(Looper.getMainLooper())
private val runnable = object : Runnable {
override fun run() {
// 使用弱引用
weakRef.get()?.updateUI()
}
}
private val weakRef = WeakReference(this)
fun correctWay() {
handler.postDelayed(runnable, 10000)
}
override fun onDestroy() {
handler.removeCallbacksAndMessages(null)
super.onDestroy()
}
}
2. Handler 消息优先级
private val handler = Handler(Looper.getMainLooper())
fun demonstratePriority() {
// 普通消息
handler.post {
Log.d("Priority", "普通消息")
}
// 异步消息(高优先级)
val asyncMsg = Message.obtain(handler) {
Log.d("Priority", "异步消息")
}
asyncMsg.isAsynchronous = true
handler.sendMessage(asyncMsg)
// 插入同步屏障
val token = handler.postSyncBarrier()
// 屏障后的普通消息被阻塞
handler.post {
Log.d("Priority", "被阻塞的普通消息")
}
// 异步消息可以越过屏障
val asyncMsg2 = Message.obtain(handler) {
Log.d("Priority", "越过屏障的异步消息")
}
asyncMsg2.isAsynchronous = true
handler.sendMessage(asyncMsg2)
// 移除屏障
handler.removeCallbacksAndMessages(token)
}
}
3. Handler 与协程对比
private val handler = Handler(Looper.getMainLooper())
// Handler 方式
fun handlerWay() {
Thread {
// 后台工作
val result = doWork()
handler.post {
// 回到主线程
updateUI(result)
}
}.start()
}
// 协程方式
fun coroutineWay() {
CoroutineScope(Dispatchers.Main).launch {
val result = withContext(Dispatchers.IO) {
doWork()
}
updateUI(result)
}
}
private fun doWork(): String {
Thread.sleep(1000)
return "工作完成"
}
private fun updateUI(result: String) {
Log.d("Compare", "更新 UI: $result")
}
}
4. Handler 性能优化
private val handler = Handler(Looper.getMainLooper())
private val messagePool = mutableListOf<Message>()
// 消息复用
fun optimizedPost() {
val msg = obtainMessage()
msg.what = 1
msg.obj = "数据"
handler.sendMessage(msg)
}
private fun obtainMessage(): Message {
return if (messagePool.isNotEmpty()) {
messagePool.removeAt(0)
} else {
Message.obtain()
}
}
private fun recycleMessage(msg: Message) {
msg.recycle()
messagePool.add(msg)
}
}
面试题总结
基础题
- Handler 的作用是什么?
- 线程间通信、定时任务、延迟执行
- Handler 的消息机制是怎样的?
- Looper 循环取消息 → Handler 处理消息
- 为什么主线程不会因为 Looper.loop() 而阻塞?
- 使用 epoll 机制,无消息时进入等待状态
进阶题
- 延时消息的原理是什么?
- 按时间排序,使用 epoll 等待
- 消息屏障的作用是什么?
- 阻塞普通消息,只处理异步消息
- 异步消息的使用场景有哪些?
- VSync 信号、输入事件、系统消息
高级题
- Handler 内存泄漏如何避免?
- 使用静态内部类、弱引用、及时移除
- IdleHandler 的使用场景?
- 启动优化、预加载、清理任务
- IntentService 与普通 Service 的区别?
- 单线程、自动停止、队列处理
- Handler 与协程的对比?
- Handler 更底层、协程更高级抽象