系列文章索引
Android系统启动流程
LayoutInflater源码详解
更新
录播回放已上传,请戳链接食用:【Android/源码/面试】LayoutInflater源码详解
前言
这篇文章会从源码的角度分析,LayoutInflater将xml文件实例化为一个view对象的流程
我们会发现,其中有两个部分是耗时的主要来源
- XmlResourseParser对xml的遍历
- 反射创建View对象导致的耗时
这两点,又跟Xml的复杂程度成正相关,Xml越复杂,则递归调用所消耗的时间就越长,就产生了我们所说的,卡顿问题
整体流程概览

LayoutInflater的创建
概览
LayoutInflater是一个抽象类,它的创建,并不是交由App层处理的,而是调用了from()的静态函数,经由系统服务LAYOUT_INFLATER_SERVICE,最终创建了一个LayoutInflater的子类对象–PhoneLayoutInflater
重要函数解析
LayoutInflater.from(cxt)
这个函数比较简单,就是根据传递过来的Context对象,调用getSystemService()来获取对应的系统服务,并赋值给LayoutInflater
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater = //LayoutInflate是一个系统服务,最终返回的是`PhoneLahyoutInflater`
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
而Context本身是一个抽象类,它真正的实例化对象,是ContextImpl, 在这个类的getSystemService()函数中,真正执行获取系统服务的类,是SystemServiceRegistry,其中又封装了一个ServiceFetcher来获取真正的系统服务,所有的系统服务,都是存储在一个map集合–SYSTEM_SERVICE_FETCHERS当中,这里其实是一个get方法,是从这个map集合中取出对应的系统服务
LayoutInflater
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
SystemServiceRegistry
/**
* Gets a system service from a given context.
*/
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的put函数,这个动作是交由registerService()来完成的
/**
* Statically registers a system service with the context.
* This method must be called during static initialization only.
*/
private static <T> void registerService(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}
SystemServiceRegistry这个类中有一个静态代码块,是用来完成所有服务的注册的,这里我们只关心LAYOUT_INFLATER_SERVICE对应的服务是如何注册的
static{
...
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
...
}
正如我们之前所说,这里最终是创建了一个PhoneLayoutInflater并返回的,到这里LayoutInflater的创建流程就分析完了
思考
为什么要交由系统服务来做,而不是直接创建一个PhoneLayoutInflater的实例对象?
LayoutInflater布局的实例化
整体流程
实例化的调用流程我们都很熟悉了,调用layoutInflater的inflater()函数,传入一个xml的resId参数就可以了
重要函数解析
inflate
这个函数就是我们把Xml布局文件实例化为一个View对象的入口了
LayoutInflater
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) + ")");
}
View view = tryInflatePrecompiled(resource, res, root, attachToRoot); //这段代码其实是必然返回null的,因为当前版本写死了预编译的Enable为false
if (view != null) {
return view;
}
XmlResourceParser parser = res.getLayout(resource); //获取XmlBlock.Parser对象
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
此处又调用了inflate(parser, root, attachToRoot)这个函数,来对Xml布局进行解析
这里看到对一些熟悉的标签,比如include,merge,的处理,具体细节请看下面的源码及注释
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
//XmlPullParser是一个接口
//此函数是真正执行将xml解析为视图view的过程,此处的parser为根据xml布局获取到的parser对象
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
final Context inflaterContext = mContext;
final inflateAttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0

本文从源码角度探讨Android10中LayoutInflater的工作原理,揭示复杂布局导致卡顿的原因。主要关注LayoutInflater的创建、布局实例化过程,包括inflate、rInflate和createViewFromTag()等关键函数,以及Resources获取、XmlBlock解析和预编译优化。通过理解这些流程,为解决布局卡顿问题提供优化思路。

921

被折叠的 条评论
为什么被折叠?



