我们都知道android设置显示界面时,调用setContentView方法来解析需要显示的布局文件,因此我们从这个方法开始阅读源码。
在Android studio中activity里打开setContentView方法,当你写的activity继承于Activity或者AppCompatActivity时,出现的方法是不一样的。
Activity的setContentView方法:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
AppCompatActivity的setContentView方法
public void setContentView(@LayoutRes int layoutResID) {
this.getDelegate().setContentView(layoutResID);
}
点击getDelegate()方法进去可以看到AppCompatDelegate这个类,这个类是虚类,继续点击create方法可以看到AppCompatDelegateImpl是AppCompatDelegate的实现类,在AppCompatDelegate的create方法里面可以看到window实际上是获取activity里面的mWindow(activity.getWindow())
点击getWindow方法看到直接返回的是Window类,这是个虚类,从源码注释里面可以知道PhoneWindow是他的唯一实现类,所以我们实际上需要继续看的是PhoneWindow里面的setContentView方法
public Window getWindow() {
return mWindow;
}
PhoneWindow里面我们需要关注两个方法:installDecor、mLayoutInflater.inflate
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
继续从installDecor方法进去,我们可以看到mDecor这个属性进入视线,这里做了一个判断,为空时调用了generateDecor方法,这个方法里面new了DecorView这个类对象,从源码里面可以看到DecorView其实是一个继承于FramLayout的容器ViewGroup
看完generateDecor方法知道DecorView这个类后,继续看installDecor方法,往下走,generateLayout方法出现在视线中
generateLayout方法里面,系统源码做了很多根据我们设置的app主题做的初始化特性,然后根据这些主题特性去加载了系统源码里面定义的布局资源文件来给layoutResource赋值,接下来在DecorView里面的onResourcesLoaded方法里面解析layoutResource资源文件,把解析出来的view通过addView方法添加到DecorView里**
上面解析了系统的布局文件后,这个布局文件里面一定是会包含有R.id.content这样一个容器的,通过findViewById的方式找到这个容器,返回contentParent这样的一个ViewGroup容器
/**
* The ID that the main layout in the XML layout file should have.
*/
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
总结一下:installDecor方法其实干了两件事情,一个是通过generateDecor方法初始化了顶层的DecorView,第二个是通过generateLayout方法初始化了系统资源文件,并且关联在DecorView里,找到contentParent这样的一个容器
上面我们知道了installDecor方法的作用后,我们继续看mLayoutInflater.inflate方法
mLayoutInflater.inflate(layoutResID, mContentParent);
这个方法里面唯一做的事情就是将我们外面自己设置的布局文件解析初始化,并且添加到系统基础容器contentParent里面
网友评论