Android View的加载流程

要说Android view加载流程,首先,我们需要清楚的理解什么是View、Window、Activity 以及三着有着什么样的关系。

一、什么是Activity?

看看源码中对Activity的描述:

 * An activity is a single, focused thing that the user can do.  Almost all
 * activities interact with the user, so the Activity class takes care of
 * creating a window for you in which you can place your UI with
 * {@link #setContentView}.  While activities are often presented to the user
 * as full-screen windows

Activity是 用户操作的可视化界面;它为用户提供了一个放置视图和交互操作的窗口。采用setContentView的方法提供。

因此,可以理解Activity、Window、View三者关系为。Activity提供Window ,View被添加到Window中。

以刷墙举例:

Activity可以理解为房间,Window就是房间内的墙面, 我们在墙面上可以刷各种不同的图案,这些图案就是View。


二、Activity View的加载流程

1、Activity在被创建之初,调用了attach方法,这个时候,为Activity创建了一个PhoneWindow, 并且为PhoneWindow设置了事件交互的回掉。

2、紧接着Activity的onCreate()方法被回掉。这里也就到了我们经常复写方法,我们在OnCreate()之中,调用setContentView(id)。

3、在setContentView(), PhoneWindow 创建了一个顶级视图 DecorView (FrameLayout)的子类。

4、紧接着,DecorView会依据一些feature(类似NO_ACTICON_BAR)来,添加一个layout。这个Layout中包含了Title、content。其中content也是FrameLayout,也就是我们在setContentView(id),将视图添加的父容器。

所以我们必须要在setContentView之前设置

实现全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  WindowManager.LayoutParams.FLAG_FULLSCREEN);
实现无标题栏(但有系统自带的任务栏):
requestWindowFeature(Window.FEATURE_NO_TITLE);  


更加直观的可以看作为:


我门操作的所有View都是在contentView这里,contentView作为父容器,其id为固定的 android.id.content.


三、源码分析


查看Activity的attach 方法

可以看出这个时候创建了PhoneWindow的实例。

接下来,Activity生命周期会到onCreate(),我们在onCreate方法中,调用了setContentView方法

跟进setContentView方法,看看源码做了什么

继续,调用了PhoneWindow的setContentView

重点在installDecor()方法:


我们看看 mDecor 的初始化:


mDecor 是DecorView的实例,DecorView又是FrameLayout的子类:


我们回到installDecor方法,继续往下查看generateLayout:

generateLayout()方法中,先对一系列的feature进行了判读对比,和backgroud 颜色获取等,然后通过以上feature加载一个layoutRes到decorView中。

然后在layoutRes,中找到 ID_ANDROID_CONTENT = com.android.internal.R.id.contentFrameLayout 作为我们setContentView 的容器。

此处框出的位置,就是我们返回的父容器。这里很明显返回的是ViewGroup, 就怎么认定他是FrameLayout这个子类呢??

很简单,对上诉的几个resource点击查看,发现全都是FrameLayout..


再次回到PhoneWindow#installDecor, 可以看到

  mContentParent = generateLayout(mDecor);


在PhoneWindow#installDecor继续往下看,可以看到对Title Icon这些的赋值之类。

返回到setContentView中:将我们的layoutId 解析为View,加入到mContentParent。

 mLayoutInflater.inflate(layoutResID, mContentParent);


我们在看看看LayoutInflater.inflate的过程:

其实就是解析XML ,更加xml解析为View并添加到视图关系中。

问题:view是如何根据我们的类名不同而创建的各种不同的View呢?

继续跟进以上代码,最终发现调用到了

依据类名反射创建, 到此,真个View的加载过程就完成了。

总结:

1、Activity在被创建之初,调用了attach方法,这个时候,为Activity创建了一个PhoneWindow, 并且为PhoneWindow设置了事件交互的回掉。

2、紧接着Activity的onCreate()方法被回掉。这里也就到了我们经常复写方法,我们在OnCreate()之中,调用setContentView(id)。

3、在setContentView(), PhoneWindow 创建了一个顶级视图 DecorView (FrameLayout)的子类。

4、紧接着,DecorView会依据一些feature(类似NO_ACTICON_BAR)来,添加一个layout。这个Layout中包含了Title、content。

其中content也是FrameLayout

5、然后再将我们的setContentView()的layoutId解析为View 添加到这个contentView中。


接下来, 又是如何被绘制到屏幕上的呢?请敬请等待下一章 Android View的绘制流程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章