(转)关于Android中为什么主线程不会因为Looper.loop()里的死循环卡死?引发的思考,事实可能不是一个 epoll 那么 简单。
( 转载请务必标明出处:http://www.cnblogs.com/linguanh/, 本文出自:【林冠宏(指尖下的幽灵)的博客】)
前序
本文将会把一下三个问题阐述清楚以及一个网上的普遍观点的补充:
1,安卓 APP 启动过程,对于Activity 的 onCreate 等生命周期的函数为什么不会因为 Looper.loop()里的死循环卡死而永无机会执行。
2,在 1 的基础上,View 的绘制到底是怎样完成的,它又为什么不会因为 Looper.loop()里的死循环卡死而永无机会刷新。
3,网传的观点大概如下:
1.handler机制是使用pipe来实现的
2.主线程没有消息处理时阻塞在管道的读端
3.binder线程会往主线程消息队列里添加消息,然后往管道写端写一个字节,这样就能唤醒主线程从管道读端返回,也就是说queue.next()会调用返回
4.dispatchMessage()中调用onCreate, onResume
下面的阐述中,将采用:先告知答案,再放直观图片,最后文字辅助解析的顺序。

总结:View 的底层绘制是基于Binder进程通讯触发,由底层 SurfaceFlinger 的工作线程中的事件机制,包含 handler ,looper,messageQueue 来进行接收、处理,它和 ActivityThread 的 Handler 没关系,即是与 ActivityThread 几乎无关,但是如果在ActivityThread 里面调用 View的相关函数,例如 handleMessage 的一个 setText(..),最终触发到View其它底层函数,它将会将这些信息发送到 SurfaceFlinger 的事件机制中去,被对应处理,最终刷新到界面。


1 void checkThread() {
2
3 if (mThread != Thread.currentThread()) {
4
5 throw new CalledFromWrongThreadException(
6
7 "Only the original thread that created a view hierarchy can touch its views.");
8
9 }
10
11 }

代码第三行,其中 mThread 是创建 ViewRootImpl 的线程,而ViewRootImpl是在主线程中创建的,所以,我们习惯地称它为主线程,mThread和当前代码运行的线程来做了个等式运算,相同就出错,也就是说,并不是子线程不能刷新UI,准确来说,是发送进行 UI 刷新消息的消息,因为真正的底层刷新也不是当前 APP 的主线程。而是限制了,如果当ViewRootImpl是由子线程创造的,那么就可以在该子线程中发送更新UI的消息,自然地就能更新了,那么为什么限制呢?
下面解析引自知乎
因为不光是gui,同样的道理在几乎所有编程领域里都是这样的,这背后是线程同步的开销问题。显然两个线程不能同时draw,否则屏幕会花;不能同时insert map,否则内存会花;不能同时write buffer,否则文件会花。需要互斥,比如锁。结果就是同一时刻只有一个线程可以做ui。那么当两个线程互斥几率较大时,或者保证互斥的代码复杂时,选择其中一个长期持有其他发消息就是典型的解决方案。所以普遍的要求ui只能单线程。
(转)关于Android中为什么主线程不会因为Looper.loop()里的死循环卡死?引发的思考,事实可能不是一个 epoll 那么 简单。的更多相关文章
- 关于Android中为什么主线程不会因为Looper.loop()里的死循环卡死?引发的思考,事实可能不是一个 epoll 那么 简单。
( 转载请务必标明出处:http://www.cnblogs.com/linguanh/, 本文出自:[林冠宏(指尖下的幽灵)的博客]) 前序 本文将会把一下三个问题阐述清楚以及一个网上的普遍观点的补 ...
- Android中为什么主线程不会因为Looper.loop()方法造成阻塞
很多人都对Handler的机制有所了解,如果不是很熟悉的可以看看我 如果看过源码的人都知道,在处理消息的时候使用了Looper.loop()方法,并且在该方法中进入了一个死循环,同时Looper.lo ...
- Android中线程间通信原理分析:Looper,MessageQueue,Handler
自问自答的两个问题 在我们去讨论Handler,Looper,MessageQueue的关系之前,我们需要先问两个问题: 1.这一套东西搞出来是为了解决什么问题呢? 2.如果让我们来解决这个问题该怎么 ...
- Android之Handler用法总结/安卓中只有主线程可以修改UI
Handler传递消息的方式可以实现实时刷新以及长按连续响应事件. 按钮响应 btnadd_fcl.setOnTouchListener(new View.OnTouchListener() { pr ...
- Android线程之主线程向子线程发送消息
和大家一起探讨Android线程已经有些日子了,谈的最多的就是如何把子线程中的数据发送给主线程进行处理,进行UI界面的更新,为什么要这样,请查阅之前的随笔.本篇我们就来讨论一下关于主线程向子线程如何发 ...
- ThreadLocal ——android消息机制handler在非主线程创建not called Looper.prepare() 错误的原因
引用自:https://www.jianshu.com/p/a8fa72e708d3 引出: 使用Handler的时候,其必须要跟一个Looper绑定.在UI线程可直接初始化Handler来使用.但是 ...
- android 4.0主线程訪问网络问题
在4.0下面,在主线程中訪问网络,假设请求超过6s的话,就会报ANR,那么这就会带来一个问题,假设网络慢或者请求的数据过大时,界面会卡顿,造成界面灵敏性非常差,因此网络请求一般不能放在主线程中操作,g ...
- Android 在非主线程无法操作UI意识
Android在应用显示Dialog是一个非常easy事儿,但我从来没有尝试过Service里面展示Dialog. 经验UI操作要在主线程,本地的服务Service是主线程里没错,可是远程servic ...
- [Java][Android] 多线程同步-主线程等待全部子线程完毕案例
有时候我们会遇到这种问题:做一个大的事情能够被分解为做一系列相似的小的事情,而小的事情无非就是參数上有可能不同样而已! 此时,假设不使用线程,我们势必会浪费许多的时间来完毕整个大的事情.而使用线程的话 ...
随机推荐
- hadoop HA+Federation(高可用联邦)搭建配置(一)
hadoop HA+Federation(高可用联邦)搭建配置(一) 标签(空格分隔): 未分类 介绍 hadoop 集群一共有4种部署模式,详见<hadoop 生态圈介绍>. HA联邦模 ...
- [51nod1666] 最大值
题面 题解 毒瘤题浪费我大好青春 容易知道, 如果\(l\)和\(r\)位数不一样, 直接选形似\(99..99\)的数, 输出答案即可 \(l\)和\(r\)位数一样的话, 当位数确定的时候, 由于 ...
- Elasticsearch删除数据之_delete_by_query
es参考版本:elasticsearch:5.5 _delete_by_query会删除所有query语句匹配上的文档,用法如下: curl -X POST "localhost:9200/ ...
- 事务四大特性(ACID)
事务的概念:事务是指逻辑上的一组操作,这组操作要么同时完成要么同时不完成. 事务的管理:默认情况下,数据库会自动管理事务,管理的方式是一条语句就独占一个事务. 如果需要自己控制事务也可以通过如下命令开 ...
- vue 循环加载动态组件以及传值
今天遇到一个需求,某个页面是个动态页面,由多个子组件构成. 之前我们的做法是将N个需要的组件import进主页面,然后引用一下即可.但是现在遇到的问题是, 这个动态页面存在多个业务,有的业务需要某几个 ...
- Netfilter 之 连接跟踪相关数据结构
Netfilter通过连接跟踪来记录和跟踪连接的状态,为状态防火墙和NAT提供基础支持: 钩子点与钩子函数 下图为钩子点和钩子函数的关系图(点击图片查看原图),其中ipv4_conntrack_def ...
- antd源码分析之——折叠面板(collapse)
官方文档 https://ant.design/components/collapse-cn/ 目录 一.antd中的collapse 代码目录 1.组件结构图(♦♦♦重要) 2.源码节选:antd/ ...
- 2.JSON.stringify()Object
JSON.stringify() JSON 通常用于与服务端交换数据. 在向服务器发送数据时一般是字符串. 我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符 ...
- Python接口测试-利用登录后的session用到登录后的接口中
有些接口是在登录后才能调用的,例如“立即出借”只有在登录后才能到出借窗口,解决: 主要是添加了: s =requests.session() 完整代码: '''登录 ''' print('*'*100 ...
- Mysql查询某字段重复值并删除重复值
1.查询重复值: select code,count(*) as count from hospital group by code having count>1; 该语句查询code重复值大于 ...