2024年3月27日发(作者:)
前言
Android
的消息机制主要是指
Handler
的运行机制,对于大家来说
Handler
已经是轻车熟路了,可是真的掌握了
Handler
?本文主要通过几个问题围绕着
Handler
展开深入并拓展的了解。
站在巨人的肩膀上会看的更远。大家有兴趣的也可以到
Gityuan
的博客上多了解了解,全部都是干货。而且他写
的东西比较权威,毕竟也是小米系统工程师的骨干成员。
Questions
1.
Looper
死循环为什么不会导致应用卡死,会消耗大量资源吗?
2. 主线程的消息循环机制是什么(死循环如何处理其它事务)?
3.
ActivityThread
的动力是什么?(
ActivityThread
执行
Looper
的线程是什么)
4.
Handler
是如何能够线程切换,发送
Message
的?(线程间通讯)
5. 子线程有哪些更新
UI
的方法。
6. 子线程中
Toast
,
showDialog
,的方法。(和子线程不能更新
UI
有关吗)
7. 如何处理
Handler
使用不当导致的内存泄露?
8.
Looper
死循环为什么不会导致应用卡死?
线程默认没有
Looper
的,如果需要使用
Handler
就必须为线程创建
Looper
。我们经常提到的主线程,也叫
UI
线程,
它就是
ActivityThread
,
ActivityThread
被创建时就会初始化
Looper
,这也是在主线程中默认可以使用
Handler
的原
因。
首先我们看一段代码
new Thread(new Runnable() {
@Override
public void run() {
Log.e("qdx", "step 0 ");
e();
xt(, "run on Thread", _SHORT).show();
Log.e("qdx", "step 1 ");
();
Log.e("qdx", "step 2 ");
}
}).start();
我们知道
();
里面维护了一个死循环方法,所以按照理论,上述代码执行的应该是
step 0 –>step 1
也
就是说循环在
e();
与
();
之间。
在子线程中,如果手动为其创建了
Looper
,那么在所有的事情完成以后应该调用
quit
方法来终止消息循环,否则这个子
线程就会一直处于等待(阻塞)状态,而如果退出
Looper
以后,这个线程就会立刻(执行所有方法并)终止,因此建议
不需要的时候终止
Looper
。
执行结果也正如我们所说,这时候如果了解了
ActivityThread
,并且在
main
方法中我们会看到主线程也是通过
Looper
方式来维持一个消息循环。
public static void main(String[] args) {
eMainLooper();//
创建
Looper
和
MessageQueue
对象,用于处理主线程的消息
ActivityThread thread = new ActivityThread();
(false);//
建立
Binder
通道
(
创建新线程
)
if (sMainThreadHandler == null) {
sMainThreadHandler = dler();
}
nd(_TAG_ACTIVITY_MANAGER);
();
//
如果能执行下面方法,说明应用崩溃或者是退出了
...
throw new RuntimeException("Main thread loop unexpectedly exited");
}
那么回到我们的问题上,这个死循环会不会导致应用卡死,即使不会的话,它会慢慢的消耗越来越多的资源
吗?
对于线程即是一段可执行的代码,当可执行代码执行完成后,线程生命周期便该终止了,线程退出。而对于主线程,我
们是绝不希望会被运行一段时间,自己就退出,那么如何保证能一直存活呢?简单做法就是可执行代码是能一直执行下
去的,死循环便能保证不会被退出,例如,
binder
线程也是采用死循环的方法,通过循环方式不同与
Binder
驱动进行读
写操作,当然并非简单地死循环,无消息时会休眠。但这里可能又引发了另一个问题,既然是死循环又如何去处理其他
事务呢?通过创建新线程的方式。真正会卡死主线程的操作是在回调方法
onCreate/onStart/onResume
等操作时间过长,
会导致掉帧,甚至发生
ANR
,
本身不会导致应用卡死。
主线程的死循环一直运行是不是特别消耗
CPU
资源呢?
其实不然,这里就涉及到
Linux pipe/epoll
机制,简单说就是在主
线程的
MessageQueue
没有消息时,便阻塞在
loop
的
()
中的
nativePollOnce()
方法里,此时主线程会释放
CPU
资
源进入休眠状态,直到下个消息到达或者有事务发生,通过往
pipe
管道写端写入数据来唤醒主线程工作。这里采用的
epoll
机制,是一种
IO
多路复用机制,可以同时监控多个描述符,当某个描述符就绪
(
读或写就绪
)
,则立刻通知相应程序
进行读或写操作,本质同步
I/O
,即读写是阻塞的。
所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量
CPU
资源。
Gityuan–Handler(Native
层
)
2.
主线程的消息循环机制是什么?
事实上,会在进入死循环之前便创建了新
binder
线程,在代码
()
中:
发布评论