Activity 启动流程至view绘制到屏幕显示

Activity 启动 至 view绘制 至 屏幕显示

实际效果:Activity冷启动的时候会闪黑屏,就是A启动B,这个过程中会闪黑屏,虽然网上说可以设置一个闪屏页,中间有个过渡效果,或者设置B为透明主题,这样在启动的时候就看不到黑屏了。只是感觉启动B的这个过程漫长而已,又比如说你从桌面启动A,你把A设为透明,你就会感觉你点击A之后半天没反应没启动起来,实际是有反应的哇,因为你设置的透明,所以A在启动的时候刚开始显示的透明也就是看到了桌面。这里的闪黑屏是没办法的,因为启动activty也是需要时间,安卓系统就是这样的。

我们的需求:,先启动一个系统dialog,之后启动一个activty,同时吧系统dialog消失掉,如果在activty的onResume()中消失掉系统dialog,就会闪桌面,然后才看到activity启动起来,这是因为在onResume()的时候activty并不在前台可见,你把系统dialog消失掉当然就看到桌面了,实验证明在onResume()中延时2秒再消失dialog就无缝切换了,延时不是可靠的方法,而我需要做的就是如何把不可靠变可靠,也就是知道什么时候activity的页面被添加至屏幕了。

  • 先从Activity的oncreated开始,setContentView中的view就是activty的页面
    Activity 启动流程至view绘制到屏幕显示_第1张图片
    第一步:点击setContentView方法看其调用
    Activity 启动流程至view绘制到屏幕显示_第2张图片
    第二步:再点击 setContentView 到了window这类里的setContentView方法,可惜是抽象的
    Activity 启动流程至view绘制到屏幕显示_第3张图片
    第三步:咋们找到它的子类也就是实现类查看,看这个方法到底怎么实现的
    Activity 启动流程至view绘制到屏幕显示_第4张图片
    第四步:找到它的setContentView方法
    Activity 启动流程至view绘制到屏幕显示_第5张图片
    第五步:接下来咋们关注mContentParent就ok了,我们的目的是知道mContentParent是啥时候显示在屏幕上的。接下来我们关注onCreate是被谁调用的,也就知道activty怎么起来的了,这里点不进去,点进去咋们也不知道谁调用的,那么打断点:
    调用关系如下:
    Activity 启动流程至view绘制到屏幕显示_第6张图片
    第六步:不知道是谁发了一个100的消息出来,ActivtyThread处理了重点看handleLaunchActivity方法:
    Activity 启动流程至view绘制到屏幕显示_第7张图片
    第7步:看到handleLaunchActivity里的重点方法performLaunchActivity方法
    Activity 启动流程至view绘制到屏幕显示_第8张图片
    第8步:performLaunchActivity里面有2个重点方法咋们需要关注一下:
    Activity 启动流程至view绘制到屏幕显示_第9张图片
    第9步:先看callActivityOnCreate方法如下:
    Activity 启动流程至view绘制到屏幕显示_第10张图片
    第11步:至此oncreated方法就被调用了
    Activity 启动流程至view绘制到屏幕显示_第11张图片
    第12步:然后我们再看performLaunchActivity里的performStart()其实就是在调用onStart()方法,看第8不
    Activity 启动流程至view绘制到屏幕显示_第12张图片
    第13步:至此activty的onStart()就被调用了。
    Activity 启动流程至view绘制到屏幕显示_第13张图片
    第14步:接下来咋们回到ActivtyThread这个类的handleLaunchActivity方法,里面还调用handleResumeActivity方法,这里很可疑对不对,咋们点进去:
    Activity 启动流程至view绘制到屏幕显示_第14张图片
    第15步:咋们看handleResumeActivity方法看到了performResumeActivity,这就是掉onResume的方法代码,自己点进去看,这里不分析,oncreated的流程已经梳理过了照葫芦画瓢。
    Activity 启动流程至view绘制到屏幕显示_第15张图片
    第16步:咋们接着看handleResumeActivity方法就看到了和view相关的了
    Activity 启动流程至view绘制到屏幕显示_第16张图片
    第17步:咋们看到最后一行ActivityManagerNative.getDefault().activityResumed这个方法是调用的ActivityManagerProxy这个类的activityResumed方法,咋们看到它掉了底层的native方法,底层的咋不看,至此告一段落,此时activty的页面还是没有正儿八经的显示到屏幕上去的。
    Activity 启动流程至view绘制到屏幕显示_第17张图片
    Activity 启动流程至view绘制到屏幕显示_第18张图片

至此咋们还是没有搞清楚到底何时在屏幕上显示的页面,此时屏幕上也未显示这个activty的页面,咋们继续断点dispatchMessage(Message msg)发现当收到Choreographer相关的消息时,屏幕显示了页面,咋百度查看Choreographer是和帧绘制相关的类,那么我们知道activty的页面最后是被解析成view了的,而view是需要经过measure–>layout–>draw才会到屏幕上的,而Android 每隔 16.6ms 会刷新一次屏幕,不管view是怎么draw的,按道理是在刷新的时候才会更新屏幕。也就是咋只需要找到刷新的时候并且刷的是哪个activty刷完的回调就知道了,但这里的想法是错误的,因为通过debug我们发现当一个dialog其实是刷新多次才显示成我们想要的样子,比如你设置了dialog的长宽高还有marging,断点一下你会发现它其实是经过多次刷新才显示成我们想要的样子,但不否认的就是咋还是要知道屏幕刷新完成的回调,估计这里的回调会被调用多次,毕竟每隔16.6ms就会刷一次,view也不是一次性全部绘制完成的也会不停的刷新,只是人的眼睛看不到那个变化的过程,但debug是可以看见的。

第18步:咋们断点进入了Choreographer的FrameDisplayEventReceiver的run方法,这里的targer可以看出是FrameHandler发送的消息,然后这个消息的callback不为空于是走了handleCallback方法,根据断点信息我们知道走了FrameDisplayEventReceiver的run方法
Activity 启动流程至view绘制到屏幕显示_第19张图片
Activity 启动流程至view绘制到屏幕显示_第20张图片
第19步:我们看到run方法里面走了doFrame()方法。此方法里面有3个doCallbacks方法走完,屏幕就显示了activty的页面,其中咋们重点关注CALLBACK_TRAVERSAL这种类型的消息。
Activity 启动流程至view绘制到屏幕显示_第21张图片
Activity 启动流程至view绘制到屏幕显示_第22张图片
Activity 启动流程至view绘制到屏幕显示_第23张图片
第20步:接下来我们查看doCallbacks方法
Activity 启动流程至view绘制到屏幕显示_第24张图片
Activity 启动流程至view绘制到屏幕显示_第25张图片

第21步,这里咋们就看到调用进了ViewRootImpl里去了,ViewRootImpl这个类是view的顶部视图,具体看类的介绍。咋们看到当调用doCallbacks,类型为CALLBACK_TRAVERSAL的时候,走入了ViewRootImpl的doTraversal()方法,重点看performTraversals(),自己断点进入对于源码看哦
Activity 启动流程至view绘制到屏幕显示_第26张图片
第22步:咋们进入了performTraversals发现它很长最终会调用performDraw()方法然后这个方法里面会调用mWindowSession.finishDrawing(mWindow)至此没下文了,这个方法是个远程方法,跳过此断点页面就显示了,至此也没有显示页面。

这里面有2点我没搞明白,首先是谁发的LAUNCH_ACTIVITY消息给ActivtyThread 然后调用handleLaunchActivity启动的activty,然后就是mWindowSession.finishDrawing之后页面就显示了,这里调的aidl的方法,这里是页面显示的最终调用吗?不明白

第23步:关于第一个问题,是谁发的消息,目前找到了如下,这个LAUNCH_ACTIVITY消息是属于H这个handler的,我们搜索一下谁调用谁就是发消息的:
Activity 启动流程至view绘制到屏幕显示_第27张图片
这里写图片描述

24步:接下来我们找到是这里的:
Activity 启动流程至view绘制到屏幕显示_第28张图片
25步:接下来我们看看是谁调用scheduleLaunchActivity就知道谁启动的activty了,可是怎么也找不到,于是我们从startActivty开始查找,倒着不行正着来:
Activity 启动流程至view绘制到屏幕显示_第29张图片
26步:继续往下点击就执行了execStartActivity方法
Activity 启动流程至view绘制到屏幕显示_第30张图片

27步:接下来最终调用了远程方法,使用了Binder
Activity 启动流程至view绘制到屏幕显示_第31张图片
Activity 启动流程至view绘制到屏幕显示_第32张图片

28,接下来就到了WMS里面,我这边是断点进去的,也是受这篇文章的影响http://codemx.cn/2018/01/26/AndroidOS008-Activity/,最终结果是咋们25步回调到那里去了,activty的启动过程就是如此,接下来我们看view的渲染draw终极目标。

你可能感兴趣的:(android项目开发经验)