从资源文件到控件——LayoutInflater分析
本文也发布于本人的知乎文章:https://zhuanlan.zhihu.com/p/394073666
(注:源代码为android-8.1)
0. 前言
我在我的文章《Android源码阅读分析:从Activity开始(二)——加载布局》中简单介绍了Activity
的如何加载布局的。在文章末尾提到,资源文件通过inflater
方法转换为View
。那么本篇文章就来分析一下LayoutInflater
是如何工作的。
1. 创建LayoutInflater
LayoutInflater
的构造方法被protected
修饰,也就是说,我们在创建LayoutInflater
时,不能直接使用构造方法来创建新对象。官方的推荐获取LayoutInflater
对象方式有两个:
- 通过Activity.getLayoutInflater
方法获取
- 通过Context.getSystemService
方式获取
这样能够保证获取到的LayoutInflater
对象是已经与当前context
关联上。那么,我就分别从这两个方法来看一下是如何获取对象的。
1.1 通过Activity.getLayoutInflater
获取LayoutInflater
对象
(frameworks/base/core/java/android/app/Activity.java)
public LayoutInflater getLayoutInflater() {
return getWindow().getLayoutInflater();
}
从上一篇文章中,我们知道了,Activity.getWindow
方法所得到的是一个PhoneWindow
对象,那么跟踪PhoneWindow
的getLayoutInflater
方法。
(framework/base/core/java/com/android/internal/policy/PhoneWindow.java)
public LayoutInflater getLayoutInflater() {
return mLayoutInflater;
}
哦?这里就是简简单单的返回了mLayoutInflater
。那么,我们就要看看这个变量是在哪里创建或者赋值的。
经过查找,发现在PhoneWindow
类里,只有一个地方是mLayoutInflater
变量被赋值了。
(frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java)
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
这里调用了LayoutInflater
的from
方法。
(frameworks/base/core/java/android/view/LayoutInflater.java)
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
可以看出,这里调用了context.getSystemService
方法,这与官方推荐的第二种方法相同。
1.2 通过Context.getSystemService
方式获取LayoutInflater
对象
getSystemService
是Context
的一个方法,通过传入NAME
来获取对应的Object
,然后转换为相应的服务对象。这里传入的参数值为Context.LAYOUT_INFLATER_SERVICE
。通过查找,在ContextThemeWrapper
类中找到处理Context.LAYOUT_INFLATER_SERVICE
的方法。
(frameworks/base/core/java/androidview/ContextThemeWrapper.java)
@Override
public Object getSystemService(String name) {
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
if (mInflater == null) {
mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
}
return mInflater;
}
return getBaseContext().getSystemService(name);
}
这里又调用了from(getBaseContext)
,而baseContext
通常情况下就是ContextImpl
。那么跟踪到ContextImpl
的getSystemService
方法。
(frameworks/base/core/java/android/app/ContextImpl.java)
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}