美文网首页Android知识
从源码看LayoutInflater对象的获取过程

从源码看LayoutInflater对象的获取过程

作者: ladder_builder | 来源:发表于2017-05-19 17:43 被阅读0次

LayoutInflater有多种获取方式:

  • Activity.getLayoutInflater()
  • LayoutInflater.from(context)
  • (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)
    这三种有什么不同?使用同一个context获取到的LayoutInflater是否是同一个实例?
    让我们从源码一探究竟。

Activity.java

public LayoutInflater getLayoutInflater() {
        return getWindow().getLayoutInflater();
    }
 public LayoutInflater getLayoutInflater() {
        return mLayoutInflater;
    }

Activity中用到的是PhoneWindow中的LayoutInflater

PhoneWindow.java

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

PhoneWindow中的LayoutInflater是通过LayoutInflater.from获得的。

LayoutInflater.java

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

LayoutInflater.from(context)其实还是调用的context.getSystemService, 所以三种方式其实是一样的。
context的具体实现类是ContextImpl,我们来看一下getSystemService是如何实现的。

ContextImpl.java

  1. getSystemService(name)
    private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
            new HashMap<String, ServiceFetcher>();
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }

ContextImpl中有个static的Hash表,存的是每个service对应的ServiceFetcher,具体的service是由ServiceFetcher去获取的。那再来看看ServiceFetcher是何时添加到SYSTEM_SERVICE_MAP的。

  1. Service的注册
    static {
        ... //其他service的注册
        registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
                public Object createService(ContextImpl ctx) {
                    return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
                }});
        ...
    }

在ContextImpl中有段静态代码块,其中注册了很多service的ServiceFetcher。

  1. registerService(serviceName, fetcher)
    private static int sNextPerContextServiceCacheIndex = 0;
    private static void registerService(String serviceName, ServiceFetcher fetcher) {
        if (!(fetcher instanceof StaticServiceFetcher)) {
            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
        }
        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
    }
  1. ServiceFetcher
final ArrayList<Object> mServiceCache = new ArrayList<Object>();
static class ServiceFetcher {
        int mContextCacheIndex = -1;

        /**
         * Main entrypoint; only override if you don't need caching.
         */
        public Object getService(ContextImpl ctx) {
            ArrayList<Object> cache = ctx.mServiceCache;
            Object service;
            synchronized (cache) {
                if (cache.size() == 0) {
                    // Initialize the cache vector on first access.
                    // At this point sNextPerContextServiceCacheIndex
                    // is the number of potential services that are
                    // cached per-Context.
                    for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
                        cache.add(null);
                    }
                } else {
                    service = cache.get(mContextCacheIndex);
                    if (service != null) {
                        return service;
                    }
                }
                service = createService(ctx);
                cache.set(mContextCacheIndex, service);
                return service;
            }
        }

        /**
         * Override this to create a new per-Context instance of the
         * service.  getService() will handle locking and caching.
         */
        public Object createService(ContextImpl ctx) {
            throw new RuntimeException("Not implemented");
        }
    }
abstract static class StaticServiceFetcher extends ServiceFetcher {
        private Object mCachedInstance;

        @Override
        public final Object getService(ContextImpl unused) {
            synchronized (StaticServiceFetcher.this) {
                Object service = mCachedInstance;
                if (service != null) {
                    return service;
                }
                return mCachedInstance = createStaticService();
            }
        }

        public abstract Object createStaticService();
    }

普通的ServiceFetcher会从context的mServiceCache中去取Service,还有一种静态的StaticServiceFetcher,直接从自己的缓存中取。普通的ServiceFetcher取到的Service是和context绑定的,同一个context取到的是同一个实例。而StaticServiceFetcher和context无关,任何一个context获取到的都是同一个实例。
而上面我们可以看到LayoutInflater使用的是普通的ServiceFetcher,也就是和context相关的。其创建LayoutInflater是通过PolicyManager实现的。

PolicyManager.java

public static LayoutInflater makeNewLayoutInflater(Context context) {
    return new BridgeInflater(context, RenderAction.getCurrentContext().getProjectCallback());
}

结论

  • 有的Service是和context相关的,有的是无关的。
  • 对于context相关的Service,同一个context得到的service是同一实例,不同的context得到的是不同的实例。
  • 对于context无关的Service,所有的context得到的是同一实例。
  • LayoutInflater是context相关的。

注意:此处的所谓的Service指的是通过context.getSystemService获得的对象,不一定继承于Service类,比如LayoutInflater。

相关文章

网友评论

    本文标题:从源码看LayoutInflater对象的获取过程

    本文链接:https://www.haomeiwen.com/subject/aftyxxtx.html