Android-Activity中setContentView流程解析
Posted 山水相逢-z
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android-Activity中setContentView流程解析相关的知识,希望对你有一定的参考价值。
在Activity中加载布局的时候,我们都知道调用的是setContentView方法,那么具体是如何实现的呢?
本文基于参考其他人博客以及自己翻阅源码做一个记录。
随便找到一个Activity,点击setContentView
方法可以看到实现:
public void setContentView(@LayoutRes int layoutResID)
getWindow().setContentView(layoutResID);//1
initWindowDecorActionBar();//2
layoutResID
是我们传入的布局id,所以我们先主要关注1处。可以看到这里调用了getWindow().setContentView
,点进去getWindow
看一下:
public Window getWindow()
return mWindow;
获取的是一个Window
对象,找到Window
类,它是一个抽象类,在类注释中我们可以看到下面一段:
The only existing implementation of this abstract class is
* android.view.PhoneWindow, which you should instantiate when needing a
* Window.
可以看到,Window
唯一的实现类就是PhoneWindow
。再点进去PhoneWindow
的setContentView
方法:
public class PhoneWindow extends Window implements MenuBuilder.Callback
//...
//...
//...
@Override
public void setContentView(int layoutResID)
if (mContentParent == null)
installDecor();
else
mContentParent.removeAllViews();
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed())
cb.onContentChanged();
@Override
public void setContentView(View view)
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
@Override
public void setContentView(View view, ViewGroup.LayoutParams params)
if (mContentParent == null)
installDecor();
else
mContentParent.removeAllViews();
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null && !isDestroyed())
cb.onContentChanged();
//...
//...
//...
这里我们关注setContentView(int layoutResID)实现。
当mContentParent
不为空时,会先移除其上所以子view,然后通过mLayoutInflater.inflate(layoutResID, mContentParent)
将我们的布局文件加载上去,当mContentParent
为空时,会先调用installDecor()
方法,click it:
private void installDecor()
if (mDecor == null)
mDecor = generateDecor();
//...
if (mContentParent == null)
mContentParent = generateLayout(mDecor);
//...
只看主流程代码,逻辑很清晰,mContentParent
为空的时候,会执行generateLayout()
方法,同时需要传入一个mDecor
,那么mDecor
是什么东西呢,我们可以点进generateDecor
方法看一下:
protected DecorView generateDecor()
return new DecorView(getContext(), -1);
嘿,又出来了一个DecorView
,这是个什么东西呢?查看它的源码:
private final class DecorView extends FrameLayout
可以看到,DecorView
继承FrameLayout
,是一个ViewGroup
。回到前面的generateLayout(mDecor)
,看一下我们往DecorView
里都有什么东西:
public class PhoneWindow extends Window implements MenuBuilder.Callback
protected ViewGroup generateLayout(DecorView decor)
// 此处省去一堆代码,设置窗口属性
int layoutResource;
// 此处省去一堆代码,根据不同的主题使用不同的布局资源
// 这里才是重点,向 DecorView 添加布局,并且从 DecorView 中查找出 contentParent
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null)
throw new RuntimeException("Window couldn't find content container view");
// 此处省去一堆代码设置窗口背景和标题
return contentParent;
在这个方法里,我们contentParent
其实指向的就是ID_ANDROID_CONTENT
,也就是R.id.content
。到目前为止,我们可以用一张图来概括上边儿的流程:
找到mContentParent
之后,回到setContentView
方法中:
// 解析我们设置的布局资源并且设置 mContentParent 为父布局
mLayoutInflater.inflate(layoutResID, mContentParent);
至此,我们自己的布局就加载在了Activity上,
以上是关于Android-Activity中setContentView流程解析的主要内容,如果未能解决你的问题,请参考以下文章
Android-Activity中setContentView流程解析