又来一篇源码分析文章。讲源码分析文章有的时候很虚,因为我只能讲个我看懂的大概流程,所以细节部分可以没有深入研究,看完之后也只能了解个大概。但个人觉得看源码更重要的是思路而不是细节。今天来分析下LayoutInflater的源码。
之所以分析它是因为我们来常经常使用到它,但往往只知道它是加载view的而不知它具体的实现方法。不多说直接分析。
源码分析
平常我们使用LayoutInflater最常见的方式如:
LayoutInflater inflate = LayoutInflater.from(Context context); LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
这两种方式实质上是一样的。看来LayoutInflater.from的源码:
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;
}
好吧,它就是一个披着context .getSystemService皮的狼。其实就是简单的封装了下。平常我们在获取系统的一些service如获取传感器之类的都会用到getSystemService,那么在这里context .getSystemService又是具体怎么实现的。
getSystemService
了解这个问题之前我们要清楚,Context是什么,平时我们经常说Context是上下文环境。其实Application,Activity,Service都会存在一个Context。它的具体实现类是ContextImpl。那么直接看ContextImpl:
@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
SYSTEM_SERVICE_MAP是什么。我们继续看ContextImpl的代码:
class ContextImpl extends Context {
private final static String TAG = "ContextImpl";
private final static boolean DEBUG = false;
/**
* Map from package name, to preference name, to cached preferences.
*/
private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs;
/**
* Override this class when the system service constructor needs a
* ContextImpl. Else, use StaticServiceFetcher below.
*/
/*package*/ 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();
}
private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
new HashMap<String, ServiceFetcher>();
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);
}
static {
…………
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
}});
…………
}
在虚拟机第一次加载该类时就会注册各种ServiceFatcher,包括LayoutInflater,这个是在一系列的registerService中实现的。然后将它们存储在SYSTEM_SERVICE_MAP这个HashMap中,以后要用只需从中获取,注册是在静态代码块中进行的,也就是说它只会执行一次,保证实例的唯一性。这可以说是用容器来实现的单例模式。最后通过getSystemService获取相应的Service。
我们重点关注到PolicyManager.makeNewLayoutInflate这句代码,它最终调用的是Policy中的makeNewLayoutInflate方法。
public class Policy implements IPolicy {
private static final String TAG = "PhonePolicy";
static {
// For performance reasons, preload some policy specific classes when
// the policy gets loaded.
for (String s : preload_classes) {
try {
Class.forName(s);
} catch (ClassNotFoundException ex) {
Log.e(TAG, "Could not preload class for phone policy: " + s);
}
}
}
public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}
public LayoutInflater makeNewLayoutInflater(Context context) {
return new PhoneLayoutInflater(context);
}
}
在这里看到Window具体实现类是PhoneWindow,LayoutInflater的具体实现是PhoneLayoutInflater。
PhoneLayoutInflater
看下PhoneLayoutInflater的代码。
<