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
- 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的。
- Service的注册
static {
... //其他service的注册
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
}});
...
}
在ContextImpl中有段静态代码块,其中注册了很多service的ServiceFetcher。
- 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);
}
- 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。