Android源码如何给Activity渲染布局
2017-09-22 16:35
183 查看
相信做Android应用的一些程序猿,虽然做了几个项目,但是可能还不知道我们Android系统如何给Activity渲染布局的,今天我不要脸地简单介绍一下,也算自己学习记录一下。
我们都知道,我们自己创建了XXActivity会去继承系统的Activity类,也知道Activity是通过setContentView()这个方法把布局渲染进去的。在Activity类中,我们可以找到这个方法:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
从这个方法分析,getWindow()是返回一个Window对象,我们找到Window类,在这个类中我们可以发现这个抽象方法:
public abstract void setContentView(@LayoutRes int layoutResID);
从而我们可以知道一定有一个类去继承Window这个抽象类并实现setContentView()这个方法,那么究竟是哪个类去继承它呢?上面说到在Activity类中获取Window对象可以直接调用getWindow(),从而推知在Activity类中必然也会有去创建Window这个实现类,通过查找可发现:
mWindow = new PhoneWindow(this, window);
这个时候我们就知道PhoneWindow必是Window的实现类,那么再来查找PhoneWindow这个类,通过全局查找并未找到这个类,那这个类究竟放在哪里呢?这个时候我们想到去sdk里面查找,果不其然,可以找到这个类。那么我们在PhoneWindow这个类中再去找setContentView()
这个方法的实现,如下:
@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;
}
打开mLayoutInflater.inflate(layoutResID, mContentParent)这句代码关联,跳到LayoutInflater类中:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
再点开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();
}
}
在这个方法中我们可以发现final XmlResourceParser parser = res.getLayout(resource);这是xml资源文件的解析器,然后再点开return inflate(parser, root, attachToRoot),如下:
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {......}
最终是调用这个方法。
我们都知道,我们自己创建了XXActivity会去继承系统的Activity类,也知道Activity是通过setContentView()这个方法把布局渲染进去的。在Activity类中,我们可以找到这个方法:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
从这个方法分析,getWindow()是返回一个Window对象,我们找到Window类,在这个类中我们可以发现这个抽象方法:
public abstract void setContentView(@LayoutRes int layoutResID);
从而我们可以知道一定有一个类去继承Window这个抽象类并实现setContentView()这个方法,那么究竟是哪个类去继承它呢?上面说到在Activity类中获取Window对象可以直接调用getWindow(),从而推知在Activity类中必然也会有去创建Window这个实现类,通过查找可发现:
mWindow = new PhoneWindow(this, window);
这个时候我们就知道PhoneWindow必是Window的实现类,那么再来查找PhoneWindow这个类,通过全局查找并未找到这个类,那这个类究竟放在哪里呢?这个时候我们想到去sdk里面查找,果不其然,可以找到这个类。那么我们在PhoneWindow这个类中再去找setContentView()
这个方法的实现,如下:
@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;
}
打开mLayoutInflater.inflate(layoutResID, mContentParent)这句代码关联,跳到LayoutInflater类中:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
再点开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();
}
}
在这个方法中我们可以发现final XmlResourceParser parser = res.getLayout(resource);这是xml资源文件的解析器,然后再点开return inflate(parser, root, attachToRoot),如下:
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {......}
最终是调用这个方法。
相关文章推荐
- Android源码学习之二-Activity如何管理对话框
- Android源码学习之二-Activity如何管理对话框
- Android如何确定Activity控件渲染完成
- Android源码学习之三-Activity是如何进行自动化测试的
- Android源码学习之二-Activity如何管理对话框
- Android源码学习之二-Activity如何管理对话框
- Android源码学习之三-Activity是如何进行自动化测试的
- Android布局文件的加载过程分析:Activity.setContentView()源码分析
- Android源码学习之二-Activity如何管理对话框
- 当 Activity 以全屏模式运行时,如何允许 Android 系统状态栏在顶层出现,而不迫使 Activity 重新布局让出空间
- Android源码学习之三-Activity是如何进行自动化测试的
- Android源码学习之一-Activity是如何实现主题变化的
- Android中Activity源码中是如何对对话框Dialog进行处理的
- Android源码学习之三-Activity是如何进行自动化测试的
- Android源码学习之一-Activity是如何实现主题变化的
- Android源码学习之一-Activity是如何实现主题变化的
- Android源码学习之一-Activity是如何实现主题变化的
- Android源码学习之三-Activity是如何进行自动化测试的
- Android源码学习之三-Activity是如何进行自动化测试的
- Android源码学习之二-Activity如何管理对话框