android 启动app过程,Android P APP冷启动过程全解析(之四)

经历了前面的三个阶段,activity终于初始化完毕,终终终于开始显示了和接收事件了!这就是本阶段所要做的工作:

15.新建DecorView

16.新建ViewRootImpl

17.添加到Display

18.显示

15、新建DecorView

接上一篇文章,LaunchActivityItem执行完以后,会紧接着执行ResumeActivityItem,最终执行到handleResumeActivity:

ActivityThread.handleResumeActivity(...)

ActivityThread.performResumeActivity(...)

Activity.performResume(...)

Activity.performRestart(...)

if (mStopped) {callActivityOnRestart(...)} // 回调restart

PhoneWindow.getDecorView();

if (mDecor == null) {

installDecor(); // 如果decorView还没有,则新建decorView

}

DecorView.setVisibility(View.INVISIBLE); // 将decorView设为可见,这里会触发第一次控件树遍历

其实在调用performResume之前还会调用performStart,不过activity在start的这个阶段并没有做什么真正的事情。start阶段存在的意义主要是和stop阶段相对应。

在performResumeActivity函数中,首先检查要不要调用activity.restart,如果原来activity的状态是stopped状态的,那么就需要调用,表明该activity被重新启用。对于新建的activity,是不会进行该调用的。

随后,尝试获取decorView,如果decorView为空,那么调用installDecor来新建一个。decorView是控件树的根view,继承于FrameLayout。一般情况下,我们在activity.onCreate函数中会调用setContentView函数来给activity设置显示的视图,那么在那时候decorView就已经生成了,整个控件树也会被建立。但是如果我们没有activity.onCreate函数中调用setContentView,那么系统也会在activity resume的时候自动帮我们初始化decorView,并将其设为可见。

16、新建ViewRootImpl

DecorView生成以后,整颗控件树就已经生成了,但是此时控件树还没有和窗口关联起来,关联过程如下:

WindowManager.addView(decor, layoutParams); // 向系统中添加窗口

WindowManagerGlobal.addView(...);

root = new ViewRootImpl(view.getContext(), display);

mWindowSession = WindowManagerGlobal.getWindowSession();

mChoreographer = Choreographer.getInstance();

ViewRootImpl.setView(decor, wparams...)

关联操作通过WindowManager.addView来完成,其中最重要的过程是新建ViewRootImpl。

ViewRootImpl并不是控件树的一部分,它并不是一个view,但其实现了ViewParent的接口,有且只有一个孩子DecorView。ViewRootImpl可以认为是控件树的控制器,是控件树和窗口的联系桥梁,控件树的遍历等操作都是它来控制的。ViewRootImpl在其构造函数中初始化了WindowSession和Choreographer等关键成员,前者用于和WMS进行通讯,进程唯一;而后者则是控件树遍历和事件分发的驱动者。

17、添加到Display

新建ViewRootImpl完成以后,控件树和本地窗口已经关联完成,但这一切都是发生在APP端,系统此时还不知道有一个APP要显示了,所以得请求系统为APP分配显示资源。

ViewRootImpl.setView(decor, wparams...)

requestLayout(); // 进行第一次layout

mInputChannel = new InputChannel();

IWindowSession.mWindowSession.addToDisplay(mWindow,mInputChannel,...)

mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());

view.assignParent(this); // DecorView的父节点其实是ViewRootImpl

...

在将window添加到系统中之前,要先进行第一次layout,将控件树的view都安排妥当。这里的安排妥当包括计算控件树中view的大小和位置,但不包括绘制,因为此时系统还没有给APP分配surface,无法进行绘制。之所以要在这里进行第一次layout,是因为要保证relayout在接受事件之前完成。因为在添加到WMS的同时,也建立了InputChannel,事件可能马上到来,所以addToDisplay之前调用requestLayout。

addToDisplay这个函数会在WMS中建立APP的窗口信息,决定窗口的层级,并建立事件输入通道InputChannel,至此APP的窗口已经准备完毕,就差显示内容了!

18、显示内容

前面说过,在addToDisplay之前,先调用了requestLayout,过程如下:

ViewRooImpl.requestLayout()

checkThread(); // 检查是否是主线程

ViewRooImpl.scheduleTraversals()

mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

requestLayout之后,首先通过checkThread检查是否在主线程,因此检查UI操作是否在主线程是在ViewRootImpl中进行的。因此如果我们在Activity.onCreate操作View那是没问题的,因为那时候都还没有ViewRootImpl呢。

请求layout的操作主要是往Choreographer中注册了一个TraversalRunnable的回调。在下一帧到来的时候,该回调会被执行:

TraversalRunnable.run()

ViewRooImpl.doTraversal()

ViewRooImpl.performTraversals()

if (mFirst||...){

ViewRooImpl.relayoutWindow() // 这里会分配surface

IWindowSession.relayout(mSurface,...)

if (mSurface.isValid()){

newSurface = true; // 新建surface成功

mFullRedrawNeeded = true; // 需要重新绘制

hwInitialized = ThreadedRenderer.initialize(mSurface); // 开启硬件加速

mSurface.allocateBuffers();

}

if (!cancelDraw && !newSurface) {

performDraw(); // 非首次遍历会直接draw

}else{

if (isViewVisible) {

scheduleTraversals(); // 在试一次,只发生在首次遍历的情况下

}

}

在第一次traversal的时候,ViewRooImpl会调用relayoutWindow去请求分配surface,如果surface分配成功,就初始化硬件渲染并分配buffer,最后如果view是可见的,会再请求traversal一次。这一次不会再分配surface,而是直接调用performDraw函数,绘制在surface上,然后送显,这样子界面就显示出来啦!所有流程已经完毕,over!

总结

这一阶段是activity resume以后进行工作,基本上全部都是关于view和显示的。主要的工作包括建立控件树、新建ViewRootImpl、添加到Display,分配Surface等,都是一些显示最基本、最核心的流程。通过这个流程,我们基本可以对Android的显示系统一斑窥豹了:

这里应该有个图,待画

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值