LayoutInflater源码理解

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的创建,截图如下:


图片.png

那么基于上边的分析,实现插件换肤的思路就是我们如果自己想要去拦截View的创建,就比较好拦截了,我们只需要仿照 AppCompatActivity一样,去设置 Factory即可。那么下篇文章我会给大家讲解如何拦截View的创建。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容