Android的Looper的无限循环为啥不会ANR?
借鉴自知乎https://www.zhihu.com/question/34652589,gityuan
ActivityThread中的代码
public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper();
...
Looper.loop();
Looper.prepareMainLooper();这里就开启了主线程的Looper的无限循环。但是为什么不会ANR呢?
主线程是UI线程,阻塞的话,就会掉帧。
下面转述一下gityuan大神的话
线程执行一段时间后,工作做完了,线程的生命周期就终止了。为了保活,主线程和Binder线程都是通过无限循环的方式。当然不是简单的无限循环,无消息的时候会休眠。但是又有一个问题,既然死循环,后面Activity的创建相关事务又怎么去执行?通过创建新线程的方式。
创建新线程的代码在哪
Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false);在Looper初始化代码的下方一点点thread.attach(false);这句话。会创建一个Binder线程(具体是指ApplicationThread,Binder的服务端,用于接收系统服务AMS发送来的事件),该Binder线程通过Handler将Message发送给主线程
主线程的死循环特别消耗CPU资源吗
这里就涉及到Linux pipe/epoll机制,简单说就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里。这个时候主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。
Activity的生命周期都离不开消息队列
ActivityThread的内部类H继承于Handler,在H.handleMessage(msg)方法中,根据接收到不同的msg,执行相应的生命周期。比如收到msg=H.LAUNCH_ACTIVITY,则调用ActivityThread.handleLaunchActivity()方法,最终会通过反射机制,创建Activity实例,然后再执行Activity.onCreate()等方法;再比如收到msg=H.PAUSE_ACTIVITY,则调用ActivityThread.handlePauseActivity()方法,最终会执行Activity.onPause()等方法。
主线程的消息又是哪里来的
App进程中的其他线程发送消息给主进程
图解
一个暂停Activity的流程
AMS调用ATP
ATP通过Binder传递到AT
AT发送消息到主线程
主线程在Looper中无限循环地取,当收到暂停Activity的消息,便将消息分发给ActivityThread.H.handleMessage()方法。通过一系列方法的调用,最后会调用到onPause。onPause处理完后,继续循环下去,或是阻塞。