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的显示系统一斑窥豹了:
这里应该有个图,待画
android 启动app过程,Android P APP冷启动过程全解析(之四)相关推荐
- Android启动优化实战(有效降低APP启动时间)
1.概述 手机点击一个APP,用户希望应用能够及时响应并快速加载.启动时间过长的应用不能满足这个期望,并且可能会令用户失望.这种糟糕的体验可能会导致用户在 Play 商店针对您的应用给出很低的评分,甚 ...
- android 启动优化方案,Android 项目优化(五):应用启动优化
介绍了前面的优化的方案后,这里我们在针对应用的启动优化做一下讲解和说明. 一.App启动概述 一个应用App的启动速度能够影响用户的首次体验,启动速度较慢(感官上)的应用可能导致用户再次开启App的意 ...
- android启动微信服务器,Android之高仿微信“启动画面”(一)
前记:最近忙于学业,好久没更新博客了,是时候该回来了. 其实,不单单是微信,许多应用都有启动画面. 关键方法: 1.通过Handler类实现启动画面的延时. 2.通过Intent类实现跳转到另一个Ac ...
- android 启动画面广告,Android 应用启动欢迎界面广告的实现实例
Android 应用启动欢迎界面广告 0.写在前面 在这篇教程中来实现一个类似于微信的的延迟3秒再进入主界面的效果. 1.项目准备 先新建一个空的android项目.里面只自带一个MainActivi ...
- android应用资源预编译,编译和打包全解析
我们知道,在一个APK文件中,除了有代码文件之外,还有很多资源文件.这些资源文件是通过Android资源打包工具aapt(Android Asset Package Tool)打包到APK文件里面的. ...
- android 启动画面广告,浅谈APP启动界面广告
App启动页,也称闪屏页,最初是为缓解用户等待Web/iOS/Android App数据加载的焦虑情绪而出现,后被设计师巧妙用于品牌文化展示,服务特色介绍以及功能界面熟悉等平台进行设计,被赋予了更加丰 ...
- android 启动服务权限,android – 当我尝试启动服务时权限被拒绝
我试图从Activity访问InputMethodService,我遇到了权限问题.这适用于自定义键盘应用. 我想要实现的是将在Activity中创建的文本绑定回InputMethodService. ...
- android启动其他apk,Android 启动apk的常用方法
方法一:最直接的就是知道apk的包名和启动类名, 直接启动 Intent mIntent = new Intent(); ComponentName comp = new ComponentName( ...
- android+启动脚本,imx6q android 添加开机启动脚本
1.在xx/out/target/product/sabresd_6dq/root/init.rc中添加以下内容 ========================================== ...
- android 启动一个应用,android 在一个应用中启动另一个应用
android 在一个应用中启动另一个应用 在程序开发过程当中,常遇到需要启动另一个应用程序的情况,比如在点击软件的一个按钮可以打开地图软件. startDingAppButton = (Button ...
最新文章
- epoll示例(水平触发)
- IO 模拟 1/2 Bias、1/4 Duty的 LCD 驱动
- qq模板图片asqq_重要更新 电脑编辑规则、快速滚动、富文本图片、规则模板等十多项更新!...
- 工作375-input readonly
- kvm上添加万兆网卡_烂泥:为KVM虚拟机添加网卡
- dev中循环展示图片的样式怎么写_图中的这种样式怎么用HTML写?
- 一个拖拽的效果类和dom-drag.js
- python自定义函数的关键字_Python3.x中自定义比较函数
- iOS开发的架构模式
- DataSet.Tables[].Rows[][]的用法
- 字符串怎样实例化成对象
- 合肥青少年信息学计算机竞赛试题,合肥市第二十九届青少年信息学奥林匹克竞赛(小学组)试题及部分答案...
- Cocoa与Cocoa Touch区别
- VUE子路由跳转,各位大神,为啥我这个子路由跳转不到相应的子页面,求助求助
- 著名建筑师马岩松元宇宙首作落地百度希壤 迪奥元宇宙首展同期揭幕
- 《互联网信息服务管理办法》征求意见:违规拟计入信用档案
- VBA小程序_对于选中的单元格进行取消合并_选择空值向上填充
- python 函数与部分使用示例
- 关于MNN中图像预处理
- Xilinx vivado 常用IP核使用
热门文章
- html 右边是iframe 左右结构_HTML速查表
- Enrichment plot的另一种展示
- cs python课程 加州大学_B站的CS课程整理 搬运
- 用 Python 帮运营妹纸快速搞定 Excel 文档
- Krona绘制物种或功能组成圈图
- 自动刷新某个指定网页
- 扩增子图表解读8网络图:节点OTU或类Venn比较
- R语言使用caret包构建随机森林模型(random forest)构建回归模型、通过method参数指定算法名称、通过ntree参数指定随机森林中树的个数
- R语言数据包自带数据集之ToothGrowth数据集字段解释、数据导入实战
- Python计算两个numpy数组的交集(Intersection)实战:两个输入数组的交集并排序、获取交集元素及其索引、如果输入数组不是一维的,它们将被展平(flatten),然后计算交集