博客
关于我
主线程中Looper的轮询死循环为何没有阻塞主线程?
阅读量:578 次
发布时间:2019-03-11

本文共 1262 字,大约阅读时间需要 4 分钟。

在Android系统中,主线程执行耗时操作会导致ANR(Application Not Responding)异常,这是一个开发者常需要关注的问题。ANR异常通常有两种原因:一是当前事件没有机会处理,比如主线程被阻塞,无法及时处理事件;二是正在处理的事件没有及时完成。这可能导致用户体验中的卡顿或应用崩溃。

为了避免这种问题,Android开发者通常会使用Handler消息处理机制,通过子线程执行耗时操作。然而,这一设计原理背后的逻辑并不直观,具体来说,主线程中的Looper.loop()无限循环检测消息队列有无新消息,会不会导致ANR异常?

当我们仔细看一下Looper.loop()的实现方式:它在一个死循环中不断地从消息队列中取出消息进行处理。如果主线程不退出这个循环,那么应用程序就不会退出。这是因为Android的 ActivityThread 类通过它的 main 方法执行Looper.loop(),只要这个循环继续进行,主线程就不会退出。而只有当所有消息都处理完毕后,Looper.loop()才会退出,但这种情况下通常不会发生,因为我们必须确保主线程有足够的处理能力来处理所有的事件。

那么,主线程为什么不会因为主线程的消息处理而陷入死锁呢?因为主线程的Looper-loop()只是在处理消息,它从消息队列中读取消息,实际处理消息的任务是在消息的分发端。那什么时候会发生ANR异常呢?实际上,导致ANR的原因并不是主线程被阻塞,而是主线程在处理事件的时候处理得过慢。只要主线程的消息处理速度快于事件的产生速度,就不会出现ANR。

在主线程的消息处理中,每个消息的处理时间只要不要过长,应用程序就不会出现卡顿。当用户触发某个操作时,子线程通过Handler发送消息到主线程的消息队列中,这样就不会阻塞主线程。主线程只需要轮询消息队列中的消息,而不是一直等待。因此,Looper-loop()本身不会引起主线程被阻塞,只有因为消息处理过慢才会导致ANR异常。

此外,Looper-loop()内部的实现机制也做了一些优化。消息队列会自动处理多余的消息,避免主线程被过多的消息占塞。此外,Android系统还会根据进程的优先级管理消息处理,这可以进一步保证主线程的响应能力。

所以可以说,主线程的Looper-loop()一直保持活跃状态,只是处理消息而已,自身并不阻塞。当主线程处理某个消息时,即使它占用了一定的时间,它只是在该消息处理完毕后继续处理下一个消息,而不会卡住整个主线程。这也是Android不容易出现ANR异常的重要原因。

总的来说,主线程之所以不会因为Looper-loop()而阻塞,是因为它不断地处理消息,而不是被消息所阻塞。只有当主线程在处理某个具体的消息时过于缓慢,才能导致用户感知到的卡顿或ANR异常。因此,在开发Android应用时,我们需要特别注意耗时操作的执行位置,避免在主线程中进行耗时操作,将耗时操作移至子线程,这样既保证了应用程序的响应性,又避免了ANR异常的发生。

转载地址:http://wwttz.baihongyu.com/

你可能感兴趣的文章
golang 第四课 结构体(struct)、interface{}、方法(func)详解
查看>>
element 侧菜单选中默认选中,及事件,分组
查看>>
小程序:防止父方法被子方法冒泡,使用catchtap
查看>>
PHP:php 上传文件大小控制配置文件中设置的
查看>>
TP路由地址叠加
查看>>
'ls' 不是内部或外部命令
查看>>
解决框架报错不明显:使用try和catch是关键
查看>>
正则验证:element添加动态正则验证
查看>>
vue报错 created hook错误
查看>>
Think PHP 学习笔记 10.查询方式实例演示
查看>>
JS 瀑布流效果
查看>>
单选框点击文字也能选中
查看>>
MySQL Can't connect to MySql server on 'localhost'
查看>>
使用Field II进行超声波束形成的设计仿真
查看>>
制作声场GIF动画
查看>>
此主机支持Intel VT-x,但Intel VT-x 处于禁用状态。
查看>>
golang reflect实例
查看>>
IDEA让代码飞起来,IDEA快捷键
查看>>
微信小程序学习记录之WXML事件
查看>>
zabbix监控安装
查看>>