探索Activity启动过程

研究思路:点击APP应用图标APP启动--》Activity加载并完成生命周期--》Oncreat方法下setcontentview--》view绘制

过程一:

    android源码分析

过程二:

   打开androidstudio的DDMS工具。


然后随意打开一个android APP,在DDMS上查看进程信息


从上面我们可以分析出应用程序的启动是从ActivityThread这个类的main函数开始的

来到ActivityThread的main函数


这里初始化了一个ActivityThread类本身,调用了attach方法


那我们看看getService方法是怎么样拿到一个Activity管理接口的



从这上面代码我们可以看出来系统服务通过binder通信机制调用管理ActivityManager,所以说Activity是跨进程访问

我们接着回到attach当中继续看下去, 这个时候会发现,我们调用了一个attachApplication方法,这个方法又是干嘛的?attachApplication在这里的作用实际上是ActivityManager通过getservice获取到,然后将applciationThread将其关联,把activity相关信息存储在applciationThread里面,apllicationThread的类为activity的各种状态做了相对应的准备工作

这个时候我们需要关注,ApplicationThread当中做了什么?

进入ApplicationThread中我们会看到一堆的schedle方法,这些方法的名称其实很类似于Activity的生命周期方法,代表的是在执行Activity的某种状态时调用的计划执行方法

这时我们会看到一个scheduleLaunchActivity方法,表示计划加载时调用的



这个方法很熟悉,就是创建了一个Activity对象,并设置一堆属性,然后通过消息机制将这个Activity发送出去

我们可以总结一下:当Activity状态发生变化时都会发送一个相对应的消息


从这里我们就看到了相对应的状态消息和对应的生命周期方法调用。现在可以得出结论:

Application运行的过程当中,对于Activity的操作,状态转变,实际上是通过Handler消息机制来完成的,

Application当中只管去发, 由消息机制负责调用,因为在main方法当中我门的Looper轮训器是一直在进行轮训的

在handlelanchActivity方法下调用performLaunchActivity,看到了oncreate方法的调用


至此:Activity的加载与生命周期方法都已经清楚了

过程三:setcontentview

    
getWindow获取到的android.app.Window是一个抽象类,其中setContentView()方法并没有具体的实现,而这个方法的真正实现是com.android.internal.policy.impl.PhoneWindow类

installDector我们可以看成是在做初始化,inflate是在加载布局


定义了两个参数,mDecor和mContentParent



透过注释的翻译,其实我们就能很明确知道这两个是用来干嘛的
// This is the view in which the window contents are placed. It is either(这是窗口内容放置的视图)
// mDecor itself, or a child of mDecor where the contents go.(它要么是mDecor本身,要么是mDecor的子类的内容。)
//This is the top-level view of the window, containing the window decor.(这是在窗口当中的顶层View,包含窗口的decor)

一个代表的是顶层view,一个用来装他下面的视图内容

继续往下看代码,发现了




这个地方在试图生成一个view,然后我们去看看他加载的到底是什么东西?


通过注释

//This is an optimized layout for a screen, with the minimum set of features

这是一个屏幕的优化布局,具有最小的特征集启用。

我们得出这样的结果:


这是DecorView默认的一个渲染,然后我门自己的布局都是渲染到她的FrameLayout上的
那么在这里我门现在能够明白,installDector其实实际上是在初始化两个视图容器,然后加载系统的R资源及特征,产生了一个基本布局

那么接着回到之前我们关注的另外一个方法mLayoutInflater.inflate(layoutResID, mContentParent);


这就是一个简单的加载视图

那么在这里我门就能够明白,setContentView其实做了两件比较核心的事情,就是加载环境配置,和自己的布局,那么接下来我们需要考虑的事情就是,他到底怎么画到界面上的。

过程四:View的绘制

假设Oncraet方法下只有一个setcontentview方法,那么当setcontentview执行完毕之后,调用栈继续回退,就回到了android.app.ActivityThread.handleLaunchActivity()中,调用performLaunchActivity方法之后又调用了一个handleResumeActivity在这里我发现了绘制流程的开始


Windowmanager添加view,调用了addview方法



进入addView之后我们发现了一段这样的代码,他将视图,和参数还有我门的一个ViewRoot对象都用了容器去装在了起来,那么在此处我门可以得出,是将所有的相关对象保存起来
mViews保存的是View对象,DecorView
mRoots保存和顶层View关联的ViewRootImpl对象
mParams保存的是创建顶层View的layout参数。

而在此时,有一句关键代码root.setView,这里是将我们的参数,和视图同时交给了ViewRootImpl,那么这个时候我们来看下ViewRootImpl当中的setView干了什么


省略后的代码如上所示,首先将传进来的参数view赋值给mView,这里有一点要明确ViewRootImpl其实并不是一个View的子类……因此我认为,mView将是这个对象所认识的root节点,也是整个Activity的root的节点。
接下来调用了requestLayout()方法,这个方法是有效的!

最后将view的父亲注册为自己。终于终于,mDecor知道了自己父亲是谁,或者说,整个Activity设置了一个根节点,在此之前,我们setContentView()将自己的layout布局add到PhoneWindow.mContentParent的时候,mDecor都不知道自己的parent是哪个,现在整个view的树形结构中有了根节点,也就是ViewRootImpl,那么requestLayout()就有效了,就可以进行后面的measure,layout,draw三步操作了。


该方法首先检查了是否在主线程,然后就执行了scheduleTraversals()方法。看这个方法的名字,就知道是执行一次遍历,遍历的对象就是根节点开始的view tree。


注意标记出来的Runnable对象,这个Runnable的run()方法中,调用了doTraversal()方法。而doTraversal()方法又调用了performTraversals()方法,这个方法非常长,依次调用了performMeasure(),performLayout(),performDraw()三个方法,终于开始了控件层的测量,布局,绘制三个步骤。


最后画图总结一下:

1,Activity启动过程


2,绘制流程开启



猜你喜欢

转载自blog.csdn.net/qq_25658573/article/details/80998739