1. 概述
LayoutInflater主要是用来 inflate加载我们的layout的布局文件的,而加载layout布局有3种方式,那么接下来我们就来看下 具体的方法到底是怎样的?
2. inflate加载layout布局文件的3种方法如下:
// 第一种
View layoutView = View.inflate(this , R.layout.activity_main , null) ;
// 第2种
layoutView = LayoutInflater.from(this).inflate(R.layout.activity_main , null) ;
// 第3种
layoutView = LayoutInflater.from(this).inflate(R.layout.activity_main , null , false) ;
分析:
1>:点击第一种的View.inflate()进入源码会发现,其实是调用的第2种方法:
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}
2>:点击第二种的LayoutInflater.from(this).inflate进入源码会发现,其实是调用的第3种方法:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
所以我们只需要分析第3种方法就ok,那么接下来我们先来看下是如何获取LayoutInflater.from(this)的实例的,然后再来分析如何解析View的?
3. 如何获取LayoutInflater.from(this)的?
1>:点击LayoutInflater.from(this),看到如下源码:
/**
* 获取系统的服务
*/
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return LayoutInflater;
}
2>:点击getSystemService发现是抽象类,代码如下:
public abstract Object getSystemService(@ServiceName @NonNull String name);
3>:然后我们就必须找context的实现类,也就是找ContextImpl源码,在这个类中找 getSystemService()方法即可,代码如下:
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
4>:点击getSystemService,代码如下:
public static Object getSystemService(ContextImpl ctx, String name) {
// 这个就是一个典型的单例设计模式
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
上边的SYSTEM_SERVICE_FETCHERS 是一个静态的map集合,如下:
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
对于 LayoutInflater.from(this):
1>:它是一个系统服务,早就被注册好的;
2>:同时它也是一个单例设计模式,单例就是单个实例,在内存中只有一个实例对象;
也就是说,不管我们在任何一个Activity中 获取LayoutInflater实例对象,其实都是拿的是同一个。那么接下来我们再来看第二部分,也就是 LayoutInflater.from(this).inflate()方法
4. 如何调用LayoutInflater.from(this).inflate()方法的?
1>:创建View的时候会去判断,看你是否设置了Factory,而AppCompatActivity设置了Factory,所以就拦截了,就不会执行系统的onCreateView(),而是去执行自己的onCreateView()方法的逻辑,之前验证的 如果 MainActivity继承了 AppCompatActivity,打印结果是 AppCompatImageView;
也就是说layoutInflater 会去判断 是否设置了Factory,如果没有,它会把layoutInflater设置给setFactory;
@Override
public void installViewFactory() {
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
if (layoutInflater.getFactory() == null) {
LayoutInflaterCompat.setFactory(layoutInflater, this);
} else {
}
}
2>:而上边一旦设置了setFactory,也就是说mFactory 不会空,那么它就会执行自己的onCreateView()方法,进而执行自己的一系列流程,就会执行mFactory.onCreateView(name, context, attrs)逻辑;
View的创建LayoutInflater.from(this).inflate()是通过反射创建View的;
View view;
// 前提是看你有没有设置Factory 继承AppCompatActivity他就设置了
if (mFactory2 != null) {
view = mFactory2.onCreateView(parent, name, context, attrs);
} else if (mFactory != null) {
view = mFactory.onCreateView(name, context, attrs);
} else {
view = null;
}
// 通过反射创建View
3>:AppCompatActivity它会执行自己中的方法,然后判断各种 View,从而执行自己对应的 AppCompatTextView、AppCompatImageView等等所有的View,从而达到拦截View的创建,截图如下:
