UI线程是什么
所有进程都是由zygote fork 出来的
fork 出来app之后,就会启动ActivityThread 执行main方法,创建Looper
UI为什么不能设置成线程安全的
-
UI具有可变性,甚至是高频可变性
-
UI对响应时间的敏感性要求UI操作必须高效
-
UI组件必须批量绘制来保证效率
非UI线程一定不能更新UI吗
- 间接更新UI
IO线程 进行网络请求,通过handler或者postInvalidate 通知UI更新
- SurfaceView 直接更新UI,创建一个特有的线程,加锁
地图用的GLSurfaceView openGL
TextureView 官方推荐
Hamdler 发送消息的Delay 可靠吗?
不可靠,消息太多的时候可能会出现问题
当handler post 消息过多,handlermessage 处理不过来的时候,主线程就会卡顿
调用时间也并非是delay真实的值
MessageQueue 如何处理消息?
handler的post sendMessage 等方法最终都会调用enqueueMessage 方法
如果这个消息在队列的开始,并且满足条件的话就会马上被处理,否则找到对应的位置插入进去
如果消息队列没有消息就会处于阻塞状态直到有消息过来才会去唤醒
在Looper 的loop 方法中,每次都会去调用MessageQueue 的next 方法读取下一条消息,一个死循环,在里面首先会调用nativePollOnce ,实际上是调用底层的MessageQueue ,先把底层的链表处理完,如果nextPollTimeoutMillis 为-1,在底层就会被阻塞,也就是刚刚已经处理完下面的逻辑了,message 已经没有消息了
如果不阻塞就会去执行Java层的,拿到第一条能够执行的消息,再看时间是否满足条件,如果还没到时间,就赋值给nextPollTimeoutMillis,nativePollOnce就阻塞nextPollTimeoutMillis拿到消息就return 出这条消息,退出死循环
队列优化
- 重复消息过滤
运行时高频发送相同的事件类型,可以通过判断一个合适频率移除重复消息,既要保证用户体验,同时要处理高频渲染
- 互斥消息取消
移除之前所有互斥消息
- 复用消息
当量大 需要频繁的创建消息时,使用消息池 减少GC频率
- 使用消息空闲IdleHandler 在消息队列没有消息的时候才会触发
- 使用独享的Looper
主线程的Looper 为什么不会导致应用ANR?
ANR类型
- Service Timeout
前台服务20s
后台服务200s
- BroadcastQueue Timeout
前台广播10s
后台广播60s
- ContentProvider Timeout 10s
- InputDispatching Timeout 5s
Looper是一个整体进程上的概念
ANR是执行到某一个环节的时候对开发者占用主线程耗时的一个监控,用来提示开发者,是Looper 里面的一个很小的子环节
Looper 为什么不会导致CPU 占用率高?
在消息队列里没有消息时,会调用底层的nativePoolOnce 方法,里面会调用epoll_wait 进行阻塞,当有有消息的时候调用nativtWake 进行唤醒
如何实现一个简单的handler
handler的核心能力
1.线程间通讯
2.延迟任务执行
MessageQueue 的核心能力
1.持有消息
2.消息按时间排序(优先级队列,单链表)
3.队列为空时阻塞读取
4.头节点有延时可以定时阻塞