工作之余,研究了一下Android系统的源码,准备这段时间写几篇文章做一下总结,有问题的话欢迎批评指正,本篇文章先针对LayoutInflater加载布局的过程以及原理做一些分析,网上也有不少的相关的文章,也感谢优秀的Android大牛们的分享,为我们平时的开发以及学习提供了很好的借鉴。
感谢 http://blog.csdn.net/a740169405/article/details/54580347链接的作者,为我们提供了比较好的LayoutInflater分析的相关思路。
话不多说,下面开始:
文章的重点会放在LayoutInflater加载布局文件的原理以及过程上,这里稍微提一下LayoutInflater的获取方式:
方式一:通过Context的getSystemService(String name)方法,熟悉Context的朋友应该知道,Context是一个抽象类,它有两个实现类ContextWrapper和ContextImpl,我们来看下ContextWrapper的getSystemService()方法
@Override
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
我们可以看到,该方法内部调用了mBase.getSystemService()的方法,这个mBase是ContextImpl类的对象,在这里我就不解释为什么是ContextImpl类的对象了,因为这不是本文的重点,考虑以后有时间写一篇专门介绍Context的文章,在这里知道就行了。我们来看下ContextImpl类的getSystemService()方法:
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
我用android sdk版本是26,不同的sdk版本ContextImpl中getSystemService()方法的实现可能不太一样,我们再来看一下SystemServiceRegistery.getSystemService()方法的源码
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
不管使用的sdk版本是多少,但是最终应该都会调用到上述代码来获取LayoutInflater对象,这里简单说一下,SYSTEM_SERVICE_FETCHERS是一个HasMap对象,存储了很多的服务 ,准确的说,是存储了很多服务的获取器,就是ServiceFetcher,通过获取器的getService方法,最终获取到对应的服务,除了LayoutInflater之外,还有WindowManager、ActivityManager等等。
方法二:通过LayoutInflater.from(Context context)来获取,我们来看下该方法的代码
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(String name)方法来获取对象
方法三:如果是在Activity中,可以通过Activity的getLayoutInflater方法获取,我们来看下该方法的代码
public LayoutInflater getLayoutInflater() {
return getWindow().getLayoutInflater();
}
getWindow()获得一个Window的对象,Window的实现类时PhoneWindow,我们来看下PnhoneWindow的getLayoutInflater()方法
@Override
public LayoutInflater getLayoutInflater() {
return mLayoutInflater;
}
该方法直接return了一个LayoutInflater的对象,该对象是在PhoneWindow的构造方法里创建的
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
可以看到在PhoneWindow的构造方法里面,是通过LayoutInflater.from(Context)来获得的一个LayoutInflater对象
因此上述三种方法最终都是通过Context.getSystemService()来获得的LayoutInflater对象。
下面我们来看一下LayoutInflater是怎么把xml文件转换成View的:
入口是LayoutInflater的inflate()方法,inflater有四个不同的实现方法
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root)
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
public View inflate(XmlPullParser parser, @Nullable ViewGroup root)
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)
下面我们以public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) 为例,来分析一下LayoutInflater把xml文件转换成View的原理和过程
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
我们可以看到在该方法的内部又调用了另一个三个参数的inflate方法
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) + ")");