漫画Android:Handler机制是怎么实现的?
线程之间通信会用到Handler,比如,在子线程中进行耗时的网络请求任务,子线程在获取到数据后,更新界面的时候就需要用到Handler;
子线程在获取到数据后,不直接去更新 界面,而是把数据通过一个消息 (Message) 发送出去;
主线程这边,我们提前准备好一个“接收器”——Handler 对象。这个 Handler 会专门接收子线程发来的消息,把网络请求获取的数据显示在界面上了。
安卓系统里,如果你想让不同的程序部分(我们叫它们线程)互相交流,就用到了 Handler 消息机制。这套机制有四个主要成员:
- 消息 (Message):你可以把它想象成一条生产线上的待加工的产品,线程之间要传递的信息就记录在这上面。
- 处理者 (Handler):它就像一个生产线上的工作人员。线程要发送消息,就通过 Handler 的
sendMessage()
方法把待加工的产品发出去;收到产品后,也是由 Handler 的handleMessage()
方法来读取并加工处理该产品。 - 消息队列 (MessageQueue):这就像一条流水线上的传输带,所有发出去的“产品”都会先放在这里,排着队等着被加工处理。每个线程都有且只有一条自己的“传输带”。
- 循环器 (Looper):这个角色有点像传输带的管理员。它会不停地(通过执行
loop()
方法进入一个循环)检查传输带上有没有新的“产品”。一旦发现有,它就会把产品取出来,然后递给对应的 Handler 去处理。
简单来说,就是线程A加工了一件“产品”(Message),交给自己的“工作人员”(Handler)发出去,这件产品会先放在“传输带”(MessageQueue)上。然后“传输带的管理员”(Looper)会不停地检查传输带,一看到有产品,就把它取出来,交给对应的“工作人员”(Handler)去加工处理。这样,线程之间就能顺利地传递信息了。
一个独立的Thread最多只能拥有一个Looper实例,并且每个Looper都与其唯一的MessageQueue紧密关联。因此,如果一个Thread被配置为运行消息循环(即它拥有一个Looper),那么它将精确地拥有一个Looper和一个MessageQueue。这种一对一的映射是Android健壮的异步处理模型的基础,确保了线程间通信的可预测性和安全性,尤其对于至关重要的主(UI)线程而言。
Handler的“死循环”实际上是指Looper.loop()方法,而不是Handler本身。Looper.loop()方法确实会进入一个无限循环 ,但这个循环的设计非常巧妙,它并不会导致线程卡死或CPU占用率过高。
当MessageQueue中没有消息时,Looper.loop()方法会使当前线程进入阻塞(等待)状态 。这意味着线程会暂停执行,释放CPU资源,而不是持续空转或忙碌等待。
消息驱动唤醒: 一旦有新的Message或Runnable通过Handler被发送到MessageQueue中,Looper就会被唤醒 。它会从队列中取出消息,并将其分发给相应的Handler进行处理。
因此,Looper.loop()的“死循环”是一种高效的、事件驱动的循环,它在没有任务时会主动休眠,从而避免了不必要的资源消耗和线程卡死。
ANR的发生,并非因为Looper的循环本身,而是因为开发者在主线程上执行了不应该执行的耗时操作,导致Looper无法及时处理UI事件,从而使应用程序看起来“卡死”了 。
例如在主线程中执行网络请求、复杂的计算、大型文件读写或数据库操作,在这种情况下,主线程的Looper虽然在理论上仍然运行,但它被这个耗时任务“卡住”了,无法从MessageQueue中取出并处理新的UI事件(如用户点击、屏幕绘制请求) 。
当用户在一段时间内(通常是5秒)没有得到UI响应时,Android系统就会判断应用程序无响应,并弹出ANR对话框 。
为了避免ANR,所有耗时操作都应该被放到后台线程中执行 。