前言
作为一名Android开发者肯定明白View的地位,说它占据半壁江山也不为过,作为基石之一,搞明白它的加载流程是每个开发者都应该去做的,目前网络上很多关于View绘制流程的文章,有些质量也很高,但我还是想以自己的思路出一篇文章。相信读完你对View的工作机制以及自定义View会有一个全新的认识。
1. View的绘制时机
1.1. 知识储备
- Window:每个
Activity
都会创建一个Window
用于承载View视图的显示,Window
是一个抽象类存在了一个唯一实现类PhoneWindow
- DecorView:最顶层的View,是一个
FrameLayout
子类,最终会被加载到Window当中,它内部只有一个垂直方向的LinearLayout
分为两部分:- TitleBar:屏幕顶部的状态栏
- ContentView:
Activity
对应的XML布局,通过setContentView
设置到DecorView
中。
1.2. Activity、Window、DecorView之间关系
首先来看一下Activity中setContentView源码:
public void setContentView(@LayoutRes int layoutResID) {
//将xml布局传递到Window当中
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
从代码可以看出,Activity
的setContentView
实质是将View
传递到Window
的setContentView()
方法中,Window
的setContenView
会在内部调用installDecor()
方法创建DecorView
,看一下它的部分源码:
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//初始化DecorView以及其内部的content
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
...............
} else {
//将contentView加载到DecorVoew当中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
...............
}
private void installDecor() {
...............
if (mDecor == null) {
//实例化DecorView
mDecor = generateDecor(-1);
...............
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
//获取Content
mContentParent = generateLayout(mDecor);
}
...............
}
protected DecorView generateDecor(int featureId) {
...............
return new DecorView(context, featureId, this, getAttributes());
}
通过generateDecor()
new一个DecorView
,然后调用generateLayout()
获取DecorView
中content
,最终通过inflate
将Activity
视图添加到DecorView
中的content
中,但此时DecorView
还未被添加到Window
中。添加操作需要借助ViewRootImpl
。