一 setContentView( )源码解析
我们都知道,在Activity的onCreate()方法里,通常会调用setContentView()这个方法,这个方法其实就是UI绘制的入口,我们来看一下这个方法的源码。 Activity.setContentView()
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
PhoneWindow.setContentView( ) PhoneWindow有两个十分重要的变量 mDecor :这个就是我们都知道的DecorView,它是我们顶层视图 mContentParent:这个就是DecorView里的内容,也可以说是Decorview里的子集view
@Override
public void setContentView(int layoutResID) {
installDecor();
mLayoutInflater.inflate(layoutResID, mContentParent);
}
installDecor()
private void installDecor() {
mDecor = generateDecor(-1);
mContentParent = generateLayout(mDecor);
}
generateDecor()这个方法我们不用看了,就是new了一个DecorView,我们重点来看一下generateLayout( ) 这个方法
protected ViewGroup generateLayout(DecorView decor) {
TypedArray a = getWindowStyle();
......
int layoutResource;
int features = getLocalFeatures();
......
else {
layoutResource = R.layout.screen_simple;
}
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource){
final View root = inflater.inflate(layoutResource, null);
if (mDecorCaptionView != null) {
if (mDecorCaptionView.getParent() == null) {
addView(mDecorCaptionView,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mDecorCaptionView.addView(root,
new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
};
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
return contentParent;
}
Ok,现在我们就创建了DecorView已经初始化了这个布局,接下来就是加载我们自己的布局了,也就是setContentView()传入的资源ID里的布局。我们再回到setContentView()方法中的第二个调用 mLayoutInflater.inflate(layoutResID, mContentParent);
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
root.addView(temp, params);
}
二 具有兼容性的AppCompatActivity的setContentView
现在的android版本我们创建的是AppCompatActivity,并不是Activtiy,其实它们本质上都是一样的,只是AppCompatActivity解决了一些兼容性的问题,mContentParent对应的布局有所变化,但是对应的资源ID因为在源码中进行了替换,所以资源ID还是R.id.content,这里简单的看一下源码: AppCompatActivity.setContentView( )
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
*AppCompatDelegateImpl.setContentView()
@Override
public void setContentView(View v, ViewGroup.LayoutParams lp) {
ensureSubDecor();
ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
contentParent.addView(v, lp);
mOriginalWindowCallback.onContentChanged();
}
AppCompatDelegateImpl.ensureSubDecor()
private void ensureSubDecor() {
mSubDecor = createSubDecor();
}
AppCompatDelegateImpl.createSubDecor()
private ViewGroup createSubDecor() {
final ContentFrameLayout contentView = (ContentFrameLayout) subDecor.findViewById(
R.id.action_bar_activity_content);
final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
if (windowContentView != null) {
while (windowContentView.getChildCount() > 0) {
final View child = windowContentView.getChildAt(0);
windowContentView.removeViewAt(0);
contentView.addView(child);
}
windowContentView.setId(View.NO_ID);
contentView.setId(android.R.id.content);
}
三 流程图
ok,此时Decorview算是正式把我们的布局添加到里面去了,但是只是添加,并没有进行我们熟悉的测量,布局,绘制这三个步骤,下一篇我们重点来讲一下UI绘制最重要的这三个步骤。下图为上面的流程图:
|