前言
点击Launcher的应用图标,到应用的主页展示到屏幕的过程中,Android系统是如何将画面渲染出来的?
本文将分析应用启动时View相关的代码,理解启动期间View的相关代码,理解View
、Window
、WindowManager
、ViewRootImpl
和Activity
之间的关系。
启动
我们都知道Android应用进程的入口是ActivityThread
的main方法。在经过与system_server
的一系列IPC交互后,最终AMS会发起EXECUTE_TRANSACTION
的命令,启动category为android.intent.category.LAUNCHER
的Activity,走到了ActivityThread.performLaunchActivity
方法:
1 | // ActivityThread.java |
从源码可以看到,在应用启动时,会调用到Activity的attach方法,之后马上就会回调Activity的onCreate方法,看看attach内部做了什么:
1 | // Activity.java |
可以看到,调用到Activity的attach方法时,会为Activity创建一个Window
,并为这个Window
设置好WindowManager
。
设置的WindowManager
是哪个类的实例?点进去看看:
1 | // Window.java |
原来WindownManager
是通过WindowManagerImpl
的createLocalWindowManager
创建而来的,而WindowManagerImpl
的parentWindow,就是上面Activity在attach时创建的Window,即PhoneWIndow
。
此后,performLaunchActivity结束,Activity的状态置为ON_CREATE
。
AMS又再发起EXECUTE_TRANSACTION
的命令,回调Activity的onStart方法,此时Activity开始可见:
1 | // ActivityThread.java |
至此,Activity开始可见,准备开始获取焦点。
获取焦点
AMS发起EXECUTE_TRANSACTION
的命令,试图将Activity的生命周期扭转为RESUMED
状态,于是代码就走到了ActivityThread
的handleResumeActivity
方法:
1 | // ActivityThread.java |
在handleResumeActivity
中,从启动的activity中获取DecorView
和WindowManager
之后,会将DecorView
纳入WindowManager
的管理。看看addView内部做了什么:
1 | // WindowManagerImpl.java |
mGlobal是WindowManagerGlobal
,如其命名,是一个进程下的全局WindowManager,维护View
和Window
的关系。
看看WindowManagerGlobal
的addView内部做了什么:
1 | // WindowManagerGlobal.java |
WindowManagerGlobal
内部创建了一个ViewRootImpl
实例,并把view,也就是DecorView
给设置到ViewRootImpl
里面去。setView十分重要,内部请求重新布局,并且Window开始获取焦点:
1 | // ViewRootImpl.java |
经过WindowSession
的addToDispalyAsUser方法后,Window获取到了焦点,回调到DecorView
的onWindowFocusChanged。在获取焦点前,有一个关键的requestLayout方法,内部Choregrapher
请求VSync信号后,就开始的View的三大流程:测量、布局和绘制。先看看VSync信号的请求流程。
VSync信号
requestLayout十分重要,内部先开启Handler的同步屏障,而后Choregrapher
开始等待vsync信号,信号到达,回调TraversalRunnable
,开始执行View树的遍历:
1 | // ViewRootImpl.java |
关键在postCallback,Choregrapher
会在合适的时机回调TrasversalRunnable
,会在什么时机?点进去看看:
1 | // Choregrapher.java |
从代码可以看出,postCallback内部调用到了scheduleFrameLocked,请求VSync信号。mDisplayEventReceiver
内部调用了native方法,在此不做赘述。
VSync信号到达,会回调到FrameDisplayEventReceiver
的onVsync方法:
1 | // Choregrapher.FrameDisplayEventReceiver.java |
VSync信号到达,FrameDisplayEventReceiver
会发送一个带有callback的异步消息到Handler中,而后就会回调到FrameDisplayEventReceiver
的run方法,执行Choregrapher
的doFrame方法:
1 | // Choregrapher.java |
在doFrame内部调用到doCallbacks,doCallbacks内部Choregrapher
会找到CALLBACK_TRAVERSAL
类型的callback,并回调他的run方法,在CallbackRecord
内部会调用到真正的callback,也就是前面传入的mTraversalRunnable
。
至此,开始调用ViewRootImpl
的doTraversal方法,进一步调用performTraversal方法,正式进入View的三大流程: 测量、布局以及绘制:
1 | // ViewRootImpl.java |
总结
从上面的分析可知,一个Activity
对应一个Window
,这个Window
就是PhoneWindow
,而其管理类便是WindowManager
,对应WindowManagerImpl
。这个WindowManagerImpl
内部持有一个WindowManagerGlobal
,统一管理当前应用进程的所有Window
。
在Activity
的Resume阶段,通过WindowManagerGlobal
的addView将DecorView
和ViewRootImpl
绑定在一起,形成一个View树,最终调用requestLayout,启动View(DecorView
)的三大流程:测量、布局以及绘制。
在启动阶段的整体流程:
- 在
Activity
回调onCreate前,ActivityThread
会为Activity
创建一个Window
,并为这个Window
设置一个WindowManager
; - 在
Activity
回调onStart后,ActivityThread
会把这个Activity
设置为可见; - 在
Activity
回调onResume后,会通过WindowManagerGlobal
创建一个ViewRootImpl
,此后通过ViewRootImpl
请求第一次布局,在通过Choregrapher
请求第一次VSync信号;之后收到VSync信号后,执行performTraversals,正式进入View的三大流程: 测量、布局以及绘制。