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("");

    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进程中的其他线程发送消息给主进程

图解

Android的Looper的无限循环为啥不会ANR?_第1张图片

一个暂停Activity的流程

AMS调用ATP

ATP通过Binder传递到AT

AT发送消息到主线程

主线程在Looper中无限循环地取,当收到暂停Activity的消息,便将消息分发给ActivityThread.H.handleMessage()方法。通过一系列方法的调用,最后会调用到onPause。onPause处理完后,继续循环下去,或是阻塞。

你可能感兴趣的