本文包含Application启动,Activity启动,ViewTree创建,ViewRootImp解析,Choreographer解析,同步刷新信号处理等内容
- 首先通过fork创建出进程后,执行Main方法,完成如下步骤
1.创建Activity Thread
-
在ActivityThread被创建完毕后,首先会调用attach(),最终调用ActivityManagerService.attachApplication()方法,里面分别创建了Application和Activity
最终将ApplicationThread thread对象传递给AMS,AMS通过thread传递数据到当前进程
1.1.Application创建
- 通过ActivityThread.bindApplication()方法完成创建
源码流程
-
将入参效验后构造成AppBindData并通过Handler传递到主线程
-
Handler接受到消息后通过handleBindApplication()处理任务
-
创建Instrumentation 对象,ActivityThread持有该对象引用
Application、Activity 的创建都是需要调用instrumentation相关方法
-
通过Instrumentation创建Application
是通过反射创建出Application
-
将ContextImpl对象赋值给Application的mBase引用
-
app创建完毕,调用方法通知
通过调用Application的onCreate方法通知App创建完毕
-
1.2.Activity创建
- 通过ActivityTaskManagerService.attachApplication()方法完成创建
源码流程
-
mStackSupervisor.realStartActivityLocked()方法启动Activity
-
在**ActivityThread.handleLaunchActivity()**方法之中做初始化工作
-
初始化WindowManagerService
-
在performLaunchActivity()之中通过Instrumentation实现反射创建Activity
-
属性关联
创建PhoneWindow,设置触摸/物理按键事件分发,焦点变化,依附/去依附 window等 引用Instrumentation 记录token 记录Application 标题 创建windowManager,并作为Window的成员变量 .....等属性都完成关联
-
通过Instrumentation,通知Activity回调其onCreate方法
-
设置ActivityLifecycleCallbacks
-
2.开启Looper循环
3.onCreate()
- 通过getDelegate().setContentView(layoutResID)关联布局,最终连接为ViewTree结构
源码流程
- 创建DecorView,并将AppCompatDelegateImpl mWindow赋值给DecorView mWindow变量
- PhoneWindow mDecor 引用持有DecorView对象,即DecorView与PhoneWindow相互持有对方
- 取出DecorView里名为content的子view,并将其里面的子view移除
- 加载自定义的layout,构建View树
4.添加View
- 通过addView()完成View添加
源码流程
- 从Activity中取出Window并设置布局属性,取出DecorView设置INVISIBLE
- 调用WindowManager.AddView()
- 交由WindowManagerGlobal处理
- 创建ViewRootImpl对象
- 设置DecorView的layoutParam,默认是填充父控件
- 可能会有多个DecorView,因此需要List来记录相关信息
- 调用ViewRootImpl.setView()
- 调用requestLayout()开启三大流程
- 调用WindowSession.addToDisplay()方法
- 添加至WindowManagerService,即添加Window到底层
- 注册事件监听,分发native层触摸事件/物理键至WindowInputEventReceiver
- 记录 ViewParent
5.requestLayout()
- 此方法是ViewRootImpl里的请求方法
源码流程
- 检查线程是不是主线程,如果不是,则抛出异常
- 标记需要进行layout
- 调用scheduleTraversals()方法,开始请求
- 标记一次绘制请求,屏蔽短时间内的重复请求
- 向主线程Looper队列里放同步屏障消息,用来控制异步消息的执行
- 将mTraversalRunnable放入mChoreographer队列里
Choreographer
- Choreographer类是ViewRootImpl构造时候创建的,通过ThreadLocal方式获取
- 内部有DisplayEventReceiver子类,用来接送底层刷新信号
- 入队方法根据时间控制是立即时间还是异步执行
- 最后调用到DisplayEventReceiver.scheduleVsync()
- scheduleVsync是native 方法,注册同步脉冲信号事件,底层每16ms刷新一次,如果上层没有注册同步脉冲信号事件,则底层刷新的时候不会通知上层。
6.接受信号
-
通过**FrameDisplayEventReceiver.onVsync()**接受信号
-
构建Message,设置为异步消息,如果遇到屏障则优先执行,保证View绘制的优先级是最高的,并且调用自身方法run()方法
-
run()方法内部执行刷新消息,最终调用doFrame()方法
doFrame里取出的方法是在**mChoreographer.postCallback()**放入的
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);因此最终会回调mTraversalRunnable run方法
-
run方法内部真正执行的是doTraversal()方法
- 没有取消绘制的话则开始绘制,移除同步屏障,最终调用performTraversals()开始执行measure、layout、draw等方法
-
7.invalidate和requestLayout区别
- invalidate调用后只会触发Draw 过程,当仅仅需要重绘时调用invalidate
- requestLayout 会触发Measure、Layout过程,如果尺寸发生改变,则会调用invalidate,当涉及View的尺寸、位置变化时使用requestLayout
- 如果不确定requestLayout 是否触发invalidate,可在requestLayout后继续调用invalidate
8.子布局/父布局 Invalidate/RequestLayout 关系
子布局Invalidate
- 如果是软件绘制或者父布局开启了软件缓存绘制,父布局会走重绘过程(前提是WILL_NOT_DRAW标记没设置)。
子布局RequestLayout
- 父布局会重走Measure、Layout过程。
父布局Invalidate
- 如果是软件绘制,则子布局会走重绘过程。
父布局RequestLayout
如果父布局尺寸发生了改变,则会触发子布局Measure过程、Layout过程。
源码流程
-
构造Message,设置为异步消息,遇到屏障消息优先执行异步消息确保刷新信号能能够及时执行,也就是view绘制优先级是最高的回调是自身执行的
-
run()执行刷新消息
内部调用doFrame()方法,最后会回调mTraversalRunnable run
- 移除同步屏障
- 调用performTraversals(),开始真正的测量,布局,绘制