引子:

正如我们所知,在android中如果主线程中进行耗时操作会引发ANR(Application Not Responding)异常。

造成ANR的原因一般有两种:

    当前的事件没有机会得到处理(即主线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)
当前的事件正在处理,但没有及时完成

为了避免ANR异常,android使用了Handler消息处理机制。让耗时操作在子线程运行。

因此产生了一个问题,主线程中的Looper.loop()一直无限循环检测消息队列中是否有新消息为什么不会造成ANR?

本人面试网易的时候就被问到了T_T

源码分析

ActivityThread.java 是主线程入口的类,这里你可以看到写Java程序中司空见惯的main方法,而main方法正是整个Java程序的入口。

ActivityThread源码

public static final void main(String[] args) {
...
//创建Looper和MessageQueue
Looper.prepareMainLooper();
...
//轮询器开始轮询
Looper.loop();
...
} Looper.loop()方法

while (true) {

//取出消息队列的消息,可能会阻塞

Message msg = queue.next(); // might block



//解析消息,分发消息

msg.target.dispatchMessage(msg);



}

显而易见的,如果main方法中没有looper进行循环,那么主线程一运行完毕就会退出。这还玩个蛋啊!

总结:ActivityThread的main方法主要就是做消息循环,一旦退出消息循环,那么你的应用也就退出了。

我们知道了消息循环的必要性,那为什么这个死循环不会造成ANR异常呢?

因为Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper.loop() 的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。

也就说我们的代码其实就是在这个循环里面去执行的,当然不会阻塞了。

Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施。

如果某个消息处理时间过长,比如你在onCreate(),onResume()里面处理耗时操作,那么下一次的消息比如用户的点击事件不能处理了,整个循环就会产生卡顿,时间一长就成了ANR。

让我们再看一遍造成ANR的原因,你可能就懂了。

造成ANR的原因一般有两种:

    当前的事件没有机会得到处理(即主线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)
当前的事件正在处理,但没有及时完成

而且主线程Looper从消息队列读取消息,当读完所有消息时,主线程阻塞。子线程往消息队列发送消息,并且往管道文件写数据,主线程即被唤醒,从 管道文件读取数据,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗。

总结:Looer.loop()方法可能会引起主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理事件就不会产生ANR异常。

主线程中的Looper.loop()为什么不会造成ANR的更多相关文章

  1. 主线程中的Looper.loop()一直无限循环为什么不会造成ANR

    待归纳 https://www.jianshu.com/p/cfe50b8b0a41 https://blog.csdn.net/cjh94520/article/details/71022883 那 ...

  2. 在非主线程中更新UI

    在非主线程中调用了showMessage方法,结果报错:Can't create handler inside thread that has not called Looper.prepare() ...

  3. Linux 下子线程 exit code 在主线程中的使用

    Linux线程函数原型是这样的: void* thread_fun(void* arg) 它的返回值是 空类型指针,入口参数也是 空类型指针.那么线程的 exit code 也应该是 void * 类 ...

  4. [原]unity中WWW isDone方法只能在主线程中调用

    项目中要使用动态加载,原计划是生成WWW对象后,放到一个容器里.由一个独立线程轮询容器里的对象,如果www.isDone为true时,回调一个接口把结果交给请求方. new Thread( new T ...

  5. 主线程中也不绝对安全的 UI 操作

    从最初开始学习 iOS 的时候,我们就被告知 UI 操作一定要放在主线程进行.这是因为 UIKit 的方法不是线程安全的,保证线程安全需要极大的开销.那么问题来了,在主线程中进行 UI 操作一定是安全 ...

  6. 用Handler的post()方法来传递线程中的代码段到主线程中执行

    自定义的线程中是不能更新UI的,但是如果遇到更新UI的事情,我们可以用handler的post()方法来将更新UI的方法体,直接传送到主线程中,这样就能直接更新UI了.Handler的post()方法 ...

  7. android4.0以上访问网络不能在主线程中进行以及在线程中操作UI的解决方法

    MONO 调用一个线程操作UI 然后报Only the original thread that created a view hierarchy can touch its views.错误 goo ...

  8. 在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)

    下面的代码我调试了将近一个星期,你能够看出什么地方出了问题吗?线程函数: DWORD WINAPI ThreadProc(    while(!bTerminate)    {        // 从 ...

  9. Android中,子线程使用主线程中的组件出现问题的解决方法

    Android中,主线程中的组件,不能被子线程调用,否则就会出现异常. 这里所使用的方法就是利用Handler类中的Callback(),接受线程中的Message类发来的消息,然后把所要在线程中执行 ...

随机推荐

  1. LeetCode-096-不同的二叉搜索树

    不同的二叉搜索树 题目描述:给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数. 二叉搜索树(Binary Search ...

  2. SpringCloudStream(RabbitMQ&Kafka)&Spring-Kafka配置使用

    目录 是什么 解决问题 使用方式 创建生产者项目 pom yml 生产消息方法 接口 实现 创建消费者项目 pom yml 接收消息方法 重复消费 消费者yml 持久化 消费者负载个性配置(预拉取) ...

  3. Python安装包报错:PackagesNotFoundError: The following packages are not available from current channels

    以安装SimpleITK包为例,安装时,显示下图错误 conda install SimpleITK 按以下操作完成包安装 anaconda search -t conda SimpleITK #查询 ...

  4. MRS IoTDB时序数据库的总体架构设计与实现

    MRS IoTDB时序数据库的总体架构设计与实现 MRS IoTDB是华为FusionInsight MRS大数据套件最新推出的时序数据库产品,其领先的设计理念在时序数据库领域展现出越来越强大的竞争力 ...

  5. python安装jupyter notebooks(windows下)

    [1]前提 前提:下载好Python并把python添加到了Path路径 以3.8为例子,在安装的时候有个这个勾选项,Add Python 3.8 to PATH,勾上就好,没有的话.就把python ...

  6. BM 学习笔记

    两个 BM 哟 1.Bostan-Mori 常系数其次线性递推. 实际上这个算法是用来计算 \([x^n]\frac {F(x)}{G(x)}\) 的... 我们考虑一个神奇的多项式:\(F(x)F( ...

  7. 如何解决代码中if/else 过多的问题

    前言 if...else 是所有高级编程语言都有的必备功能.但现实中的代码往往存在着过多的 if...else.虽然 if...else 是必须的,但滥用 if...else 会对代码的可读性.可维护 ...

  8. java-Dos

    打开CMD的方式 1.菜单打开 2.Windows+R 输入cmd 3.shift+鼠标右键 选择在此处打开命令行窗口 4.资源管理器地址栏前+cmd 空格 管理员身份运行 常用的Dos命令 #盘符切 ...

  9. Git 修改历史提交信息 commit message

    修改最近一条提交的消息 git commit --amend 进入vim模式 按字母 o 或者 insert键 开始修改内容 按 esc 推出编辑,最常用的是输入":q"直接退出, ...

  10. python+pytest接口自动化(10)-session会话保持

    在接口测试的过程中,经常会遇到有些接口需要在登录的状态下才能请求,否则会提示请登录,那么怎样解决呢? 上一篇文章我们介绍了Cookie绕过登录,其实这就是保持登录状态的方法之一. 另外一种方式则是通过 ...