Android 面试| Android的Handle消息机制
Android消息机制介绍
Android消息机制中的四大概念:
ThreadLocal
:当前线程存储的数据仅能从当前线程取出。MessageQueue
:具有时间优先级的消息队列。Looper
:轮询消息队列,看是否有新的消息到来。Handler
:具体处理逻辑的地方。
过程:
- 准备工作:创建
Handler
,如果是在子线程中创建,还需要调用Looper#prepare()
,在Handler
的构造函数中,会绑定其中的Looper
和MessageQueue
。 - 发送消息:创建消息,使用
Handler
发送。 - 进入
MessageQueue
:因为Handler
中绑定着消息队列,所以Message
很自然的被放进消息队列。 Looper
轮询消息队列:Looper
是一个死循环,一直观察有没有新的消息到来,之后从Message
取出绑定的Handler
,最后调用Handler
中的处理逻辑,这一切都发生在Looper
循环的线程,这也是Handler
能够在指定线程处理任务的原因。
伪代码描述的Android主线程消息处理流程,这样会看得更清晰易懂:
// 1. 创建Handler实例,关联主线程的Looper
Handler mainHandler = new Handler(Looper.getMainLooper());
// 2. 定义消息处理逻辑
void handleMessage(Message msg) {
int what = msg.what; // 获取消息的what属性,表示消息类型
Object obj = msg.obj; // 获取消息的obj属性,携带的额外数据
// 根据消息类型执行相应的操作
switch (what) {
case MESSAGE_TYPE_ONE:
// 处理第一种类型的消息
break;
case MESSAGE_TYPE_TWO:
// 处理第二种类型的消息
break;
// ...其他case处理不同的消息类型
default:
// 默认处理逻辑
break;
}
}
// 3. 发送消息到消息队列
Message msg = obtainMessage(MESSAGE_TYPE_ONE); // 创建一个新消息,并设置类型
mainHandler.sendMessage(msg); // 发送消息到主线程的消息队列
// 4. Handler在主线程的Looper循环中处理消息
while (true) { // Looper的循环体
Message msg = mainHandler.getLooper().getMessageQueue().next(); // 从消息队列中取出一个消息
if (msg == null) {
break; // 如果消息队列为空,退出循环,而且App进程会结束
}
handleMessage(msg); // 调用handleMessage方法处理消息
}
// 5. 消息处理完成
// handleMessage方法中的代码会根据消息类型执行相应的逻辑
Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
Android中为什么主线程不会因为Looper.loop()里的死循环卡死? - Gityuan的回答 - 知乎 www.zhihu.com/question/34…
简单的总结来说:主线程也不过是运行在应用进程里面的,但实际上对于CPU来说这些进程,线程,都是一片片代码块,按照指令去执行,死循环的设计为了保证主线程能够一直存活,不会在运行一段时间后自动退出,这样App就不会无故结束掉了,而真正导致主线程卡死的操作是在回调方法如onCreate
、onStart
、onResume
等中执行时间过长。这些长时间的操作会导致界面掉帧,甚至触发应用程序无响应 ANR。然而,Looper.loop()
本身并不会导致应用卡死。当没有消息需要处理时,主线程会休眠,等待新消息的到来,不会过多占用CPU资源。
子线程一定不能更新ui么?什么时候可以?什么时候不可以。
子线程更新UI的规则:
不可以:
- 直接从子线程调用UI组件的方法,如
TextView.setText()
,Button.setEnabled()
等,这些都是不允许的。 - 在子线程中直接操作布局或者视图层次结构也是不允许的。
可以:
- 通过
Handler
将消息发送到主线程的消息队列中,然后在主线程的Handler
中处理消息并更新UI。 - 使用
AsyncTask
类,它允许在后台线程中执行耗时操作,然后在完成时将结果发布到主线程以更新UI。 - 使用
LiveData
和ViewModel
,这些是Android架构组件的一部分,它们可以在后台线程中进行数据加载,然后在主线程中观察和更新UI。 - 使用
runOnUiThread()
方法,这是Activity
类的一个方法,它允许你将一个Runnable对象发布到主线程的消息队列中,并在主线程中执行。
Activity的生命周期是怎么实现在死循环体外能够执行起来的?
实际上Activity的生命周期还是是通过Android的消息机制和Handler来实现的,依靠主线程的Looper.loop,当收到不同Message时则采用相应措施;比如收到msg=H.LAUNCH_ACTIVITY,则调用ActivityThread.handleLaunchActivity()方法,最终会通过反射机制,创建Activity实例,然后再执行Activity.onCreate()等方法;再比如收到msg=H.PAUSE_ACTIVITY,则调用ActivityThread.handlePauseActivity()方法,最终会执行Activity.onPause()等方法。
结合简单流程图和看以下的伪代码,你就更清晰的知道,Activity生命周期和Handle之间的一些细微关系,还有AMS在其中所做的一些处理:
// 伪代码表示的Android系统类和方法
class ActivityThread {
private Looper mainLooper;
private Handler mainHandler;
// 初始化主线程的Looper和Handler
function initLooperAndHandler() {
mainLooper = Looper.prepareMainLooper();
mainHandler = new Handler(mainLooper) {
override function handleMessage(Message msg) {
// 根据消息的内容执行不同的生命周期操作
switch (msg.what) {
case MSG_START_ACTIVITY:
startActivity(msg.obj); // msg.obj包含Activity的相关信息
break;
case MSG_RESUME_ACTIVITY:
resumeActivity(id); // id是Activity的标识
break;
case MSG_PAUSE_ACTIVITY:
pauseActivity(id);
break;
case MSG_STOP_ACTIVITY:
stopActivity(id);
break;
case MSG_DESTROY_ACTIVITY:
destroyActivity(id);
break;
// 其他消息处理...
}
}
}
}
// 启动Activity
function startActivity(activityInfo) {
// 创建Activity实例并调用onCreate等生命周期方法
activity = createActivityInstance(activityInfo)
activity.onCreate()
// ...
}
// 恢复Activity
function resumeActivity(id) {
activity = findActivityById(id)
activity.onResume()
// ...
}
// 暂停Activity
function pauseActivity(id) {
activity = findActivityById(id)
activity.onPause()
// ...
}
// 停止Activity
function stopActivity(id) {
activity = findActivityById(id)
activity.onStop()
// ...
}
// 销毁Activity
function destroyActivity(id) {
activity = findActivityById(id)
activity.onDestroy()
// ...
}
}
// 在Application的onCreate方法中初始化ActivityThread
ActivityThread.mainThread.initLooperAndHandler();
// 伪代码表示的Activity类
class Activity {
// 重写生命周期回调方法
function onCreate() {
// 初始化UI和数据
}
function onStart() {
// Activity开始变得可见
}
function onResume() {
// Activity准备交互
}
function onPause() {
// Activity暂停,不再交互
}
function onStop() {
// Activity不再可见
}
function onDestroy() {
// 清理资源,Activity即将被销毁
}
}
// 伪代码表示的AMS( Activity Manager Service )发送消息给ActivityThread
class AMS {
function sendMessageToActivityThread(msg) {
// 通过Binder IPC机制发送消息到ActivityThread的主线程Handler
ActivityThread.mainHandler.sendMessage(msg);
}
}
// AMS根据不同的事件向ActivityThread发送消息
AMS.sendMessageToActivityThread(MSG_START_ACTIVITY);
AMS.sendMessageToActivityThread(MSG_RESUME_ACTIVITY);
AMS.sendMessageToActivityThread(MSG_PAUSE_ACTIVITY);
AMS.sendMessageToActivityThread(MSG_STOP_ACTIVITY);
AMS.sendMessageToActivityThread(MSG_DESTROY_ACTIVITY);
以后每两天之内更新一道Android常见的面试题,以自己的角度去通俗简单易懂形式去说,不深入源码但讲基本原理,以伪代码为核心;如果你比较想问什么问题,可以评论。
转载自:https://juejin.cn/post/7352891079296073763