Android启动详解

·  阅读 655

本文包含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()方法完成创建

源码流程

  1. 将入参效验后构造成AppBindData并通过Handler传递到主线程

  2. Handler接受到消息后通过handleBindApplication()处理任务

  3. 创建Instrumentation 对象,ActivityThread持有该对象引用

    Application、Activity 的创建都是需要调用instrumentation相关方法

    1. 通过Instrumentation创建Application

      是通过反射创建出Application

    2. 将ContextImpl对象赋值给Application的mBase引用

    3. app创建完毕,调用方法通知

      通过调用Application的onCreate方法通知App创建完毕

1.2.Activity创建

  • 通过ActivityTaskManagerService.attachApplication()方法完成创建

源码流程

  1. mStackSupervisor.realStartActivityLocked()方法启动Activity

  2. 在**ActivityThread.handleLaunchActivity()**方法之中做初始化工作

    1. 初始化WindowManagerService

    2. 在performLaunchActivity()之中通过Instrumentation实现反射创建Activity

    3. 属性关联

      创建PhoneWindow,设置触摸/物理按键事件分发,焦点变化,依附/去依附 window等 引用Instrumentation 记录token 记录Application 标题 创建windowManager,并作为Window的成员变量 .....等属性都完成关联

    4. 通过Instrumentation,通知Activity回调其onCreate方法

    5. 设置ActivityLifecycleCallbacks

2.开启Looper循环

3.onCreate()

  • 通过getDelegate().setContentView(layoutResID)关联布局,最终连接为ViewTree结构

源码流程

  1. 创建DecorView,并将AppCompatDelegateImpl mWindow赋值给DecorView mWindow变量
  2. PhoneWindow mDecor 引用持有DecorView对象,即DecorView与PhoneWindow相互持有对方
  3. 取出DecorView里名为content的子view,并将其里面的子view移除
  4. 加载自定义的layout,构建View树

4.添加View

  • 通过addView()完成View添加

源码流程

  1. 从Activity中取出Window并设置布局属性,取出DecorView设置INVISIBLE
  2. 调用WindowManager.AddView()
    1. 交由WindowManagerGlobal处理
    2. 创建ViewRootImpl对象
    3. 设置DecorView的layoutParam默认是填充父控件
    4. 可能会有多个DecorView,因此需要List来记录相关信息
    5. 调用ViewRootImpl.setView()
      1. 调用requestLayout()开启三大流程
      2. 调用WindowSession.addToDisplay()方法
      3. 添加至WindowManagerService,即添加Window到底层
      4. 注册事件监听,分发native层触摸事件/物理键至WindowInputEventReceiver
      5. 记录 ViewParent

5.requestLayout()

  • 此方法是ViewRootImpl里的请求方法

源码流程

  1. 检查线程是不是主线程,如果不是,则抛出异常
  2. 标记需要进行layout
  3. 调用scheduleTraversals()方法,开始请求
    1. 标记一次绘制请求,屏蔽短时间内的重复请求
    2. 向主线程Looper队列里放同步屏障消息,用来控制异步消息的执行
    3. mTraversalRunnable放入mChoreographer队列里

Choreographer

  1. Choreographer类是ViewRootImpl构造时候创建的,通过ThreadLocal方式获取
  2. 内部有DisplayEventReceiver子类,用来接送底层刷新信号
  3. 入队方法根据时间控制是立即时间还是异步执行
  4. 最后调用到DisplayEventReceiver.scheduleVsync()
  5. scheduleVsync是native 方法,注册同步脉冲信号事件底层每16ms刷新一次,如果上层没有注册同步脉冲信号事件,则底层刷新的时候不会通知上层。

6.接受信号

  • 通过**FrameDisplayEventReceiver.onVsync()**接受信号

    1. 构建Message,设置为异步消息,如果遇到屏障则优先执行,保证View绘制的优先级是最高的,并且调用自身方法run()方法

    2. run()方法内部执行刷新消息,最终调用doFrame()方法

      doFrame里取出的方法是在**mChoreographer.postCallback()**放入的

      mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
      复制代码

      因此最终会回调mTraversalRunnable run方法

    3. run方法内部真正执行的是doTraversal()方法

      1. 没有取消绘制的话则开始绘制,移除同步屏障,最终调用performTraversals()开始执行measure、layout、draw等方法

7.invalidate和requestLayout区别

  1. invalidate调用后只会触发Draw 过程,当仅仅需要重绘时调用invalidate
  2. requestLayout 会触发Measure、Layout过程,如果尺寸发生改变,则会调用invalidate,当涉及View的尺寸、位置变化时使用requestLayout
  3. 如果不确定requestLayout 是否触发invalidate,可在requestLayout后继续调用invalidate

8.子布局/父布局 Invalidate/RequestLayout 关系

子布局Invalidate

  • 如果是软件绘制或者父布局开启了软件缓存绘制,父布局会走重绘过程(前提是WILL_NOT_DRAW标记没设置)。

子布局RequestLayout

  • 父布局会重走Measure、Layout过程。

父布局Invalidate

  • 如果是软件绘制,则子布局会走重绘过程。

父布局RequestLayout

如果父布局尺寸发生了改变,则会触发子布局Measure过程、Layout过程。

源码流程

  1. 构造Message,设置为异步消息,遇到屏障消息优先执行异步消息确保刷新信号能能够及时执行,也就是view绘制优先级是最高的回调是自身执行的

  2. run()执行刷新消息

    内部调用doFrame()方法,最后会回调mTraversalRunnable run

    1. 移除同步屏障
    2. 调用performTraversals(),开始真正的测量,布局,绘制
分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改