经历了前面的三个阶段,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的显示系统一斑窥豹了:

这里应该有个图,待画

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

  1. Android启动优化实战(有效降低APP启动时间)

    1.概述 手机点击一个APP,用户希望应用能够及时响应并快速加载.启动时间过长的应用不能满足这个期望,并且可能会令用户失望.这种糟糕的体验可能会导致用户在 Play 商店针对您的应用给出很低的评分,甚 ...

  2. android 启动优化方案,Android 项目优化(五):应用启动优化

    介绍了前面的优化的方案后,这里我们在针对应用的启动优化做一下讲解和说明. 一.App启动概述 一个应用App的启动速度能够影响用户的首次体验,启动速度较慢(感官上)的应用可能导致用户再次开启App的意 ...

  3. android启动微信服务器,Android之高仿微信“启动画面”(一)

    前记:最近忙于学业,好久没更新博客了,是时候该回来了. 其实,不单单是微信,许多应用都有启动画面. 关键方法: 1.通过Handler类实现启动画面的延时. 2.通过Intent类实现跳转到另一个Ac ...

  4. android 启动画面广告,Android 应用启动欢迎界面广告的实现实例

    Android 应用启动欢迎界面广告 0.写在前面 在这篇教程中来实现一个类似于微信的的延迟3秒再进入主界面的效果. 1.项目准备 先新建一个空的android项目.里面只自带一个MainActivi ...

  5. android应用资源预编译,编译和打包全解析

    我们知道,在一个APK文件中,除了有代码文件之外,还有很多资源文件.这些资源文件是通过Android资源打包工具aapt(Android Asset Package Tool)打包到APK文件里面的. ...

  6. android 启动画面广告,浅谈APP启动界面广告

    App启动页,也称闪屏页,最初是为缓解用户等待Web/iOS/Android App数据加载的焦虑情绪而出现,后被设计师巧妙用于品牌文化展示,服务特色介绍以及功能界面熟悉等平台进行设计,被赋予了更加丰 ...

  7. android 启动服务权限,android – 当我尝试启动服务时权限被拒绝

    我试图从Activity访问InputMethodService,我遇到了权限问题.这适用于自定义键盘应用. 我想要实现的是将在Activity中创建的文本绑定回InputMethodService. ...

  8. android启动其他apk,Android 启动apk的常用方法

    方法一:最直接的就是知道apk的包名和启动类名, 直接启动 Intent mIntent = new Intent(); ComponentName comp = new ComponentName( ...

  9. android+启动脚本,imx6q android 添加开机启动脚本

    1.在xx/out/target/product/sabresd_6dq/root/init.rc中添加以下内容 ========================================== ...

  10. android 启动一个应用,android 在一个应用中启动另一个应用

    android 在一个应用中启动另一个应用 在程序开发过程当中,常遇到需要启动另一个应用程序的情况,比如在点击软件的一个按钮可以打开地图软件. startDingAppButton = (Button ...

最新文章

  1. epoll示例(水平触发)
  2. IO 模拟 1/2 Bias、1/4 Duty的 LCD 驱动
  3. qq模板图片asqq_重要更新 电脑编辑规则、快速滚动、富文本图片、规则模板等十多项更新!...
  4. 工作375-input readonly
  5. kvm上添加万兆网卡_烂泥:为KVM虚拟机添加网卡
  6. dev中循环展示图片的样式怎么写_图中的这种样式怎么用HTML写?
  7. 一个拖拽的效果类和dom-drag.js
  8. python自定义函数的关键字_Python3.x中自定义比较函数
  9. iOS开发的架构模式
  10. DataSet.Tables[].Rows[][]的用法
  11. 字符串怎样实例化成对象
  12. 合肥青少年信息学计算机竞赛试题,合肥市第二十九届青少年信息学奥林匹克竞赛(小学组)试题及部分答案...
  13. Cocoa与Cocoa Touch区别
  14. VUE子路由跳转,各位大神,为啥我这个子路由跳转不到相应的子页面,求助求助
  15. 著名建筑师马岩松元宇宙首作落地百度希壤 迪奥元宇宙首展同期揭幕
  16. 《互联网信息服务管理办法》征求意见:违规拟计入信用档案
  17. VBA小程序_对于选中的单元格进行取消合并_选择空值向上填充
  18. python 函数与部分使用示例
  19. 关于MNN中图像预处理
  20. Xilinx vivado 常用IP核使用

热门文章

  1. html 右边是iframe 左右结构_HTML速查表
  2. Enrichment plot的另一种展示
  3. cs python课程 加州大学_B站的CS课程整理 搬运
  4. 用 Python 帮运营妹纸快速搞定 Excel 文档
  5. Krona绘制物种或功能组成圈图
  6. 自动刷新某个指定网页
  7. 扩增子图表解读8网络图:节点OTU或类Venn比较
  8. R语言使用caret包构建随机森林模型(random forest)构建回归模型、通过method参数指定算法名称、通过ntree参数指定随机森林中树的个数
  9. R语言数据包自带数据集之ToothGrowth数据集字段解释、数据导入实战
  10. Python计算两个numpy数组的交集(Intersection)实战:两个输入数组的交集并排序、获取交集元素及其索引、如果输入数组不是一维的,它们将被展平(flatten),然后计算交集