引子:

正如我们所知,在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. [ Skill ] print println printf fprintf sprintf lsprintf

    https://www.cnblogs.com/yeungchie/ 几种 print 函数的差异 print 接收任意的数据类型,并打印到 CIW print( 12345 ) ; 12345 pr ...

  2. 【VR游戏】封神榜传

    领悟导入SteamVR和VRTK,SteamVR要和CameraRig位置保持一致.1.可以创建多个scene,然后进行连接跳转.但是创建好之后要自己重新导回scene附:删除MainCamera,添 ...

  3. Laravel常用工具类

    工具类函数 Geom转成字符串 如果项目中有大量的计算经纬度需求,强烈建议使用PgSql的geometry类型 public static function formatGeomToStr($geom ...

  4. Java有了synchronized,为什么还要提供Lock

    摘要:在Java中提供了synchronized关键字来保证只有一个线程能够访问同步代码块.既然已经提供了synchronized关键字,那为何在Java的SDK包中,还会提供Lock接口呢? 本文分 ...

  5. 35 异常机制 异常处理机制 异常处理五个关键字 try、catch、finally、throw、thorws 代码

    异常处理机制 概念 抛出异常 捕获异常 异常处理五个关键字 try.catch.finally.throw.thorws 代码 // main { int a = 1; int b = 0; // 假 ...

  6. 变量、变量作用域、常量final、变量的命名规范

    变量 变量是什么:就是可以变化的量! Java是一种强类型语言,每个变量都必须声明其类型. Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域. 注意事项: 每个变量都有类型,类 ...

  7. CF1106F题解

    居然没人写常系数齐次线性递推/jy 题意明确. 首先我们注意到这个系数是在幂上面的,这道题的各种信息都是建立在乘法上的,十分不好处理,考虑求一个 \(\ln\) 将这些信息建立在加法上. \[\ln ...

  8. chap8-fluent python

    浅拷贝 VS 深拷贝 # In[] # list 生成一个新的引用对象,只是用alst完成初始化 alst = [1,2,3,4,5] blst=list(alst) alst.append(6) p ...

  9. SSM集成Thymeleaf

    创建项目 Spring+SpringMVC+MyBatis的配置文件 数据库内容 dao层+service层+controller层 映射文件 前端简单页面 配置tomcat,运行显示 总体项目架构 ...

  10. spring——IOC理论

    这里主要是对于IOC理论提出的一个认识 dao接口 public interface Fruit { String getFruit(); } dao接口的实现类 public class Fruit ...