LayoutInflater的获取和来源解析

LayoutInflater 是个重要的工具类,在android中经常被用到,犹如findViewById一般,findViewById找的是控件view,LayoutInflater找的则是布局layout。

LayoutInflater的获取有几种方法,个人比较喜欢
 LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
这种写法,显得比较有内涵。context是一个上下文,Context.LAYOUT_INFLATER_SERVICE是一个常量字符串。为什么这样能获取到,稍后再分析。

LayoutInflater提供静态方法,可以获取到自身的一个对象,
LayoutInflater inflater = LayoutInflater.from(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;
    }
惊奇的发现,居然是第一种写法的封装,同时加上非空判断,更加完善。


在activity中,可以直接调用
  LayoutInflater inflater = getLayoutInflater();
这个方法是调用getWindow().getLayoutInflater();获得的,
 public Window getWindow() {
        return mWindow;
    }
getWindow()获取的是当前activity的窗口对象mWindow,mWindow实际上是个PhoneWindow对象,看一下源码,

public LayoutInflater getLayoutInflater() {
        return mLayoutInflater;
    }

 public PhoneWindow(Context context) {
        super(context);
        mLayoutInflater = LayoutInflater.from(context);
    }

在PhoneWindow创建时,就获取了mLayoutInflater对象。这时发现居然是调用了第二种写法。
这三中方法一样,都是调用了同一种方法。那么,context.getSystemService(str)是如何运行的?
在activity中直接掉用该方法,可以发现
@Override
    public Object getSystemService(@ServiceName @NonNull String name) {
        if (getBaseContext() == null) {
            throw new IllegalStateException(
                    "System services not available to Activities before onCreate()");
        }

        if (WINDOW_SERVICE.equals(name)) {
            return mWindowManager;
        } else if (SEARCH_SERVICE.equals(name)) {
            ensureSearchManager();
            return mSearchManager;
        }
        return super.getSystemService(name);
    }
调用super.getSystemService(name),那么继续看
 @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);
    }
有了,进入判断正好,拿到LayoutInflater对象,看清楚,是个clone对象。

在非activity中用上下文调用context.getSystemService(str)时,这是要看context的源码,
public abstract Object getSystemService(@ServiceName @NonNull String name);
Context是个抽象类,我们需要找到它的实体类,是ContextImpl,在activity中的上下文实际上是这个实现类
@Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }

继续进入SystemServiceRegistry
 public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }

private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();

SYSTEM_SERVICE_FETCHERS是一个map集合,key value 的一一对应关系,
 static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }
是个内部接口类,用到了泛行。
既然是从集合里获取,那么就应该有往集合里放的代码
static {
 registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
                new CachedServiceFetcher<LayoutInflater>() {
            @Override
            public LayoutInflater createService(ContextImpl ctx) {
                return new PhoneLayoutInflater(ctx.getOuterContext());
            }});
    }

 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);
    }

静态模板快,说明加载且只加载一次。registerService()方法,既然把接口传入map中,要么new一个接口,要么用一个类实现接口,CachedServiceFetcher是什么,

static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
        private final int mCacheIndex;

        public CachedServiceFetcher() {
            mCacheIndex = sServiceCacheSize++;
        }

        @Override
        @SuppressWarnings("unchecked")
        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            synchronized (cache) {
                // Fetch or create the service.
                Object service = cache[mCacheIndex];
                if (service == null) {
                    service = createService(ctx);
                    cache[mCacheIndex] = service;
                }
                return (T)service;
            }
        }

        public abstract T createService(ContextImpl ctx);
    }

由于是抽象类,所以在new一个对象时,要重写抽象方法。ruturn 为什么是PhoneLayoutInflater呢?因为
LayoutInflater也是个抽象类,可以用它的静态方法,如果要new的话,用个子类继承它。PhoneLayoutInflater是它的子类。
这下就清楚了,SystemServiceRegistry类在app启动时会被调用,static代码块运行一次,把LayoutInflater加载进去,成一个全局单例的模式,
其他的一些全局单例
WindowManager windowManager =
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
等等都是一个道理,看懂了一个,其他的加载获取也就都明白了。

总结,获取LayoutInflater的三种方法

LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

LayoutInflater inflater = LayoutInflater.from(context);


LayoutInflater inflater = getLayoutInflater();

按个人喜好选取。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值