一、问题
问 1:主线程因为 Looper.loop() 是死循环的,那为什么主线程不会因为死循环卡死?
主线程确实是死循环的,但是在开启死循环之前,执行了 thread.attach(false)
这一步就创建了新的线程,建立了 Binder 通道,也即创建了服务端和应用端通信的通道,可以理解创建了 Binder 线程
此时系统进程和应用进程通过 Binder 可以进行跨进程通信,没毛病,即死循环保证的是应用不异常退出,死循环还能处理其他事务是因为在死循环之前开启了新的线程,对事务的处理在新线程中完成
对于事务的处理要反馈给主线程时,是通过 Binder 跨进程调用,然后通过主线程的 Handler 切换到应用进程完成消息的处理
问 2:主线程死循环是不是很消耗 CPU 资源呢?
不不不,这里涉及到 Linux 的 pipe/epoll 机制,当主线程的消息队列没有消息时,会阻塞在 Queue#next()
中的 nativePollOnce()
方法中
此时主线程会释放 CPU 资源进入休眠状态,直到下一个消息到来
这里主线程休眠,就存在唤醒主线程的操作,该操作是通过往 pipe 管道写端写入数据来唤醒主线程
因此,主线程没消息的时候就睡眠了,不会消耗大量 CPU 资源
问 3:主线程的消息从哪来?
其他线程通过 Handler 发送给主线程
二、补问
问 :安卓 APP 启动过程,对于 Activity#onCreate() 等生命周期为什么不会因为 Looper#loop() 里的死循环而无机会执行
答:Activity 的生命周期方法是通过 Binder 跨进程通信实现的,跨进程通信中系统进程不受 Looper#loop() 的死循环的影响(不在同一个线程),系统进程通知应用进程调用 Activity 的生命周期方法,首先通过 ActivityThread 内部的 Handler#handleMessage() 切换线程到主线程,再通过 Handler 完成 Activity 的生命周期方法的调用
三、Activity 生命周期流程
第一步:ActivityThread#main()
// 准备 Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 开始 loop 的死循环
Looper.loop();
// 不会执行到这里,到这里就抛异常了
throw new RuntimeException("Main thread loop unexpectedly exited");
第二步:ActivityThread#attach()
// 获取 AMS 服务
final IActivityManager mgr = ActivityManager.getService();
mgr.attachApplication(mAppThread) // Binder 调用,进入 AMS 所在进程
AMS#attachApplicationLocked()
ActivityThread#bindApplication()
ActivityThread#sendMessage(H.BIND_APPLICATION, data) // 回到应用进程
handleBindApplication()
// 1. 获取 Application(此时 Application 为空,反射创建)
// 2. 设置 appContext.setOuterContext(app),这里的 appContext 对应 Application
app = data.info.makeApplication(data.restrictedBackupMode, null);
// 调用 Application#onCreate()
mInstrumentation.callApplicationOnCreate(app);
ActivityStackSupervisor#attachApplicationLocked(app)
realStartActivityLocked()
app.thread.scheduleLaunchActivity
ActivityThread$ApplicationThread#scheduleLaunchActivity() // Binder 调用,进入 AMS 所在进程
ActivityThread#sendMessage(H.LAUNCH_ACTIVITY, r) // 回到应用进程
handleLaunchActivity()
// 1. 创建 Activity,再次调用 LoadApk#makeApplication() 获取 Application(上面已经创建了,这里直接返回)
// 2. 通过 Instrumentation#callActivityOnCreate(),最终调用 Activity#onCreate()
// 3. appContext.setOuterContext(activity),这里的 appContext 对应 Activity
Activity a = performLaunchActivity(r, customIntent);
handleResumeActivity()
// ActivityClientRecord 通过 token 获取对应 Activity,调用 Activity#performResume(),然后通过 Instrumentation#callActivityOnResume() 调用 Activity#onResume()
performResumeActivity()
// 给 Window 赋值(Window 在哪被创建的?在上面的 Activity#attach() 方法中,mWindow 被赋值为 PhoneWindow)
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
// 设置 Activity 可见
decor.setVisibility(View.INVISIBLE);
// 开启 View 的绘制流程
// 其中完成了 ViewRootImpl 创建(当前在主线程)
// ViewRootImpl#checkThread() 方法用来检测更新 UI 是否为主线程,子线程更新 UI 会抛异常
// 但在 ViewRootImpl 创建之前,在子线程中可以更新 UI
wm.addView(decor, l);