本文基于 SDK-33
前面四篇文章单独分析了 Handler 机制中四个最主要的部分,那么纵观全局来查看一下整个 Handler 机制的工作过程:
在线程中创建 Handler。
如果是在子线程中创建,还需手动创建 Looper 对象,并调用 Looper.loop 开启轮询。
如果是在主线程创建,则无需手动创建 Looper,因为系统已经自从创建并开启了 loop
开启 loop 之后,此时 Looper 中的 MessageQueue 还没有消息,此时 native 层会一直等待,Looper 的 loop 循环也会一直处于等待 MessageQueue 的 next 方法返回 Message 的状态中。
通过 Handler 对象发送 Message,调用 MessageQueue 的 enqueueMessage 方法将消息压入自身维护的队列中,并在确定是否唤醒 native 层。
如果插入的 Message 唤醒了 MessageQueue,则 Looper 调用的 next 方法可以获取到 Message,然后就可以调用 Message 绑定的 target(Handler)对象的 dispatchMessage
方法了。
dispatchMessage
方法会将 Message 交由 handleCallback
或者 handleMessage
处理。
handleMessage 执行之后,Looper 会将 Message 回收。
整个流程大致上就是上面这样的。
MessageQueue 和 Thread 都是 Looper 对象的变量,也就是说,Looper 和 MessageQueue 和 Thread 是绑定的,是一一对应的关系。
在 Looper 中维护了一个 ThreadLocal 对象,以保证一个线程的整个生命周期只会和一个 Looper 进行绑定。
在任何线程内都可以创建 Handler,都可以和 mainLooper 进行关联,所以 Handler 和 Looper 是一对多的关系。
不一定。
handleMessage 运行在哪个线程,主要看 Handler 绑定的 Looper 是在哪个线程创建和 loop 的,因为 Looper 的 next 方法最终会调用 Handler 的 handleMessage。
Handler 作为匿名内部类或非静态内部类时,会持有外部 Activity 的引用,当 Activity 退出时,如果还存在着未处理的消息时,会导致 Activity 无法及时被回收,从而导致内存泄漏。
处理方式:
WeakReference
来引用 Activity。系统自己为主线程创建了 Looper,并调用了 loop 方法,是在 ActivityThrad 类的 main 方法中创建的:
public static void main(String[] args) {
......
Looper.prepareMainLooper();
......
Looper.loop();
......
}
在 ActivityThread 中也维护了一个 Handler,在其 handleMessage 中收到 EXIT_APPLICATION
消息时,会调用 mainLooper 的 quit 方法:
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case BIND_APPLICATION:
......
case EXIT_APPLICATION:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
Looper.myLooper().quit();
break;
......
}
......
}
postMessage 会为 Message 设置一个 callback 回调,在 Handler 处理消息时,会先检查传递过来的 Message 是否已经设置了 callback,如果已经设置了,则将该消息交由 callback 处理,如果没有设置 callback 回调,会查看是否为 Handler 设置 callback 回调,如果 Handler 设置了,则消息交由 Handler 的 Callback.handleMessage 处理,如果 Handler 也没有设置 Callback,则交由 handlemessage 处理消息。
在 Android 中,IdleHandler
接口用于实现一个回调机制,在系统处于空闲状态且没有待处理的用户界面事件时触发。IdleHandler
的目的是允许应用程序在系统不忙于其他活动时执行后台任务,例如预加载数据或更新用户界面。
在 MessageQueue 的 next 方法中,如果 MessageQueue 中没有消息,会进行阻塞,在阻塞之前,还会判断是否存在 IdleHandler,如果存在,就会去执行 IdleHandler 的 queueIdle 方法,如果不存在,才会阻塞队列。
需要注意的是,IdleHandler
不适用于长时间运行的任务或需要立即处理的任务,因为它可能会被不频繁地调用且持续时间很短。对于这些类型的任务,应使用其他机制,如线程或服务。
名字包含 Handler,实际就是个 Thread,只不过内部实现了 Looper,无须我们手动创建而已。