LayoutInflater from(Context context) 流程
Android LayoutInflater from(@UiContext Context context)的代码如下:
public static LayoutInflater from(@UiContext Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
调用参数context的getSystemService()方法,得到实例LayoutInflater,然后将它返回。
参数context一般都是Activity实例,所以看下Activity的getSystemService(),如下:
@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);
}
参数name目前是Context.LAYOUT_INFLATER_SERVICE,所以继续调用父类ContextThemeWrapper的getSystemService()方法,如下:
@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);
}
这里找到对应的参数LAYOUT_INFLATER_SERVICE,当第一次调用该方法的时候,成员变量mInflater 是null,所以又调用了LayoutInflater.from()方法,不过注意了,参数不同了,参数是getBaseContext(),然后又调用了cloneInContext(this)方法,复制了一个。
从上面还可以看到,Activity的getSystemService()方法,在参数为WINDOW_SERVICE、SEARCH_SERVICE、LAYOUT_INFLATER_SERVICE是进行的单独处理,为其他参数时,是调用的getBaseContext().getSystemService(name)。
Activity的getBaseContext()得到的是它的成员变量mBase,看代码知,mBase也是Context类型,Activity也是Context类型。它俩有什么不同呢,其实,mBase是ContextImpl实例,Activity的Context类里的函数功能,都是通过mBase来实现的,这里是使用了代理模式。
ContextImpl的getSystemService()方法
接着看下ContextImpl的getSystemService()方法,如下:
@Override
public Object getSystemService(String name) {
if (vmIncorrectContextUseEnabled()) {
// Check incorrect Context usage.
if (WINDOW_SERVICE.equals(name) && !isUiContext()) {
final String errorMessage = "Tried to access visual service "
+ SystemServiceRegistry.getSystemServiceClassName(name)
+ " from a non-visual Context:" + getOuterContext();
final String message = "WindowManager should be accessed from Activity or other "
+ "visual Context. Use an Activity or a Context created with "
+ "Context#createWindowContext(int, Bundle), which are adjusted to "
+ "the configuration and visual bounds of an area on screen.";
final Exception exception = new IllegalAccessException(errorMessage);
StrictMode.onIncorrectContextUsed(message, exception);
Log.e(TAG, errorMessage + " " + message, exception);
}
}
return SystemServiceRegistry.getSystemService(this, name);
}
调用了SystemServiceRegistry的getSystemService()方法,如下:
/**
* Gets a system service from a given context.
* @hide
*/
public static Object getSystemService(ContextImpl ctx, String name) {
if (name == null) {
return null;
}
final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
if (fetcher == null) {
if (sEnableServiceNotFoundWtf) {
Slog.wtf(TAG, "Unknown manager requested: " + name);
}
return null;
}
final Object ret = fetcher.getService(ctx);
if (sEnableServiceNotFoundWtf && ret == null) {
// Some services do return null in certain situations, so don't do WTF for them.
switch (name) {
case Context.CONTENT_CAPTURE_MANAGER_SERVICE:
case Context.APP_PREDICTION_SERVICE:
case Context.INCREMENTAL_SERVICE:
case Context.ETHERNET_SERVICE:
return null;
}
Slog.wtf(TAG, "Manager wrapper not available: " + name);
return null;
}
return ret;
}
SystemServiceRegistry的getSystemService()首先调用SYSTEM_SERVICE_FETCHERS.get(name)得到ServiceFetcher实例fetcher ,然后调用fetcher 的getService()方法,再得到具体的结果实例,最后将结果返回,这就是最终的LayoutInflater实例。
SYSTEM_SERVICE_FETCHERS是ArrayMap<String, ServiceFetcher<?>>类型,通过key值得到value,value类型是ServiceFetcher。那在这个ArrayMap里面,什么时候开始注册它的呢。
再看下ServiceFetcher类的getService(ContextImpl ctx)方法,
static abstract interface ServiceFetcher<T> {
T getService(ContextImpl ctx);
}
ServiceFetcher是一个接口,对于LayoutInflater来说,在SYSTEM_SERVICE_FETCHERS得到的fetcher是CachedServiceFetcher类型,后面再分析它的getService(ContextImpl ctx)实现
LayoutInflater在SYSTEM_SERVICE_FETCHERS中注册
它的相关注册,是在SystemServiceRegistry的static代码块中,只要开始加载SystemServiceRegistry类,就会执行。看下相关代码:
static {
//CHECKSTYLE:OFF IndentationCheck
registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
new CachedServiceFetcher<AccessibilityManager>() {
@Override
public AccessibilityManager createService(ContextImpl ctx) {
return AccessibilityManager.getInstance(ctx);
}});
…………
…………
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
…………
…………
registerService(Context.DISPLAY_HASH_SERVICE, DisplayHashManager.class,
new CachedServiceFetcher<DisplayHashManager>() {
@Override
public DisplayHashManager createService(ContextImpl ctx) {
return new DisplayHashManager();
}});
…………
…………
}
静态初始化块中,注册了好多相关的ServiceFetcher,均是通过registerService()方法。主要看与LAYOUT_INFLATER_SERVICE相关的。看下registerService()方法:
/**
* Statically registers a system service with the context.
* This method must be called during static initialization only.
*/
private static <T> void registerService(@NonNull String serviceName,
@NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
}
SystemServiceRegistry类的静态成员SYSTEM_SERVICE_NAMES是ArrayMap<Class<?>, String>类型,可以通过Class得到对应的注册服务对应的名称;SYSTEM_SERVICE_FETCHERS是 ArrayMap<String, ServiceFetcher<?>>类型,可以通过注册的名称得到对应的ServiceFetcher实例;SYSTEM_SERVICE_CLASS_NAMES是ArrayMap<String, String>类型,可以通过注册的名称得到对应的类的名称。
对于LayoutInflater,在这里可以看到注册的对应的ServiceFetcher具体是CachedServiceFetcher类型。
CachedServiceFetcher的getService(ContextImpl ctx)
分段看一下,第一段代码:
public final T getService(ContextImpl ctx) {
final Object[] cache = ctx.mServiceCache;
final int[] gates = ctx.mServiceInitializationStateArray;
boolean interrupted = false;
T ret = null;
首先取得参数ctx的成员变量mServiceCache,它的赋值mServiceCache = SystemServiceRegistry.createServiceCache()。而SystemServiceRegistry的createServiceCache():
public static Object[] createServiceCache() {
return new Object[sServiceCacheSize];
}
它每次都生成一个新Object数组,大小是sServiceCacheSize。这个大小,是上面讲述的每次调用registerService()函数,生成CachedServiceFetcher实例的时候,会将sServiceCacheSize加1。它就是注册的CachedServiceFetcher实例的个数。
接着getService(ContextImpl ctx)调用ctx.mServiceInitializationStateArray得到int 数组gates。它的大小是和得到的数组cache 大小相等。
继续初始化interrupted 为false,ret为null
下面看第二段代码:
for (;;) {
boolean doInitialize = false;
synchronized (cache) {
// Return it if we already have a cached instance.
T service = (T) cache[mCacheIndex];
if (service != null) {
ret = service;
break; // exit the for (;;)
}
// If we get here, there's no cached instance.
// Grr... if gate is STATE_READY, then this means we initialized the service
// once but someone cleared it.
// We start over from STATE_UNINITIALIZED.
// Similarly, if the previous attempt returned null, we'll retry again.
if (gates[mCacheIndex] == ContextImpl.STATE_READY
|| gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
gates[mCacheIndex] = ContextImpl.STATE_UNINITIALIZED;
}
// It's possible for multiple threads to get here at the same time, so
// use the "gate" to make sure only the first thread will call createService().
// At this point, the gate must be either UNINITIALIZED or INITIALIZING.
if (gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED) {
doInitialize = true;
gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING;
}
}
进入了一个for循环中,声明一个值为false的doInitialize,接着获取到变量cache的锁,然后去cache中看是否已经存在一个缓存了。如果存在就会,将缓存结果返回了。
cache的锁在这里是用来,避免多线程情况下,gates[mCacheIndex]值设置错乱。gates是一个int数组,gates[mCacheIndex]在这里用来表示ContextImpl对应的当前服务实例生成过程走到了哪个步骤,初始的状态就是ContextImpl.STATE_UNINITIALIZED。ContextImpl.STATE_READY 表示之前成功生成过相应的服务,在LayoutInflater 这,就对应生成过LayoutInflater 实例,并且已缓存;ContextImpl.STATE_NOT_FOUND 表示之前生成相应服务的时候,没找到对应的服务。
如果gates[mCacheIndex]的值是ContextImpl.STATE_READY,则代表生成的缓存被清理了。在gates[mCacheIndex]的值是ContextImpl.STATE_READY或者ContextImpl.STATE_NOT_FOUND的情况下,先将gates[mCacheIndex] = ContextImpl.STATE_UNINITIALIZED。需要重新生成一个。
代码接着判断如果gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED,会将doInitialize = true,gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING。doInitialize = true,代表已经初始化过了,并且是通过它来实现多线程竞争状态下,只能由单个线程来执行createService()生成服务。gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING,代表正在执行createService()的过程中。gates[mCacheIndex] 为 ContextImpl.STATE_INITIALIZING,还能避免线程在执行createService()的过程中,其他的线程代码走到判断 gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED的时候,将doInitialize = true,导致多个线程执行createService()生成服务。
接着看第三段代码:
if (doInitialize) {
// Only the first thread gets here.
T service = null;
@ServiceInitializationState int newState = ContextImpl.STATE_NOT_FOUND;
try {
// This thread is the first one to get here. Instantiate the service
// *without* the cache lock held.
service = createService(ctx);
newState = ContextImpl.STATE_READY;
} catch (ServiceNotFoundException e) {
onServiceNotFound(e);
} finally {
synchronized (cache) {
cache[mCacheIndex] = service;
gates[mCacheIndex] = newState;
cache.notifyAll();
}
}
ret = service;
break; // exit the for (;;)
}
先判断doInitialize,然后调用了createService(ctx)来生成服务。createService(ctx)成功之后,会将状态设置成ContextImpl.STATE_READY。如果发生异常,状态会是ContextImpl.STATE_NOT_FOUND。最后会在finally代码中,将生成的服务service缓存起来,状态也设置到gates[mCacheIndex]中。可知,这个值可能是ContextImpl.STATE_READY,也可能是ContextImpl.STATE_NOT_FOUND。
finally 代码中,还用synchronized 加锁,并且会调用cache.notifyAll(),来唤醒在该锁上等待的线程,这个等会从下面的代码看出等待锁的线程。
生成服务之后,将它赋值给ret,跳出for循环。
createService() 生成服务
createService()的实现是在注册那块,看一下:
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}
直接生成了一个PhoneLayoutInflater对象,所以通过LayoutInflater from(Context context)得到的是一个PhoneLayoutInflater实例。它的参数是ContextImpl 类对象的getOuterContext(),它指向一个Activity实例。
接着看getService()的第四段代码:
synchronized (cache) {
while (gates[mCacheIndex] < ContextImpl.STATE_READY) {
try {
// Clear the interrupt state.
interrupted |= Thread.interrupted();
cache.wait();
} catch (InterruptedException e) {
// This shouldn't normally happen, but if someone interrupts the
// thread, it will.
Slog.w(TAG, "getService() interrupted");
interrupted = true;
}
}
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
return ret;
}
synchronized (cache)这个锁,是为了处理多线程的。如果多个线程同时调用同一个Activity的LayoutInflater.from(Context context),就可能出现多个线程同时访问getService()。但是只会1个线程去执行createService(),生成成功,再放入缓存中。其他的线程可能会走到这块加锁的代码中,然后判断gates[mCacheIndex]的值为ContextImpl.STATE_INITIALIZING,小于ContextImpl.STATE_READY,所以通过cache.wait(),等待createService()完成。
第三段代码中,咱们分析了,在createService()完成之后,会调用cache.notifyAll()来唤醒在该锁上等待的线程。线程唤醒之后,还会通过while循环去判断,这个时候,gates[mCacheIndex]的值已经是ContextImpl.STATE_READY或ContextImpl.STATE_NOT_FOUND,不满足循环的条件,会跳出while循环。接着又会进入for循环中,这个时候再从缓存中获取的,就能获取到值了。
最后就是将结果ret返回。
PhoneLayoutInflater类的cloneInContext(Context newContext)
在前面ContextThemeWrapper的getSystemService()里调用LayoutInflater.from(getBaseContext())返回结果LayoutInflater类实例之后,还会调用LayoutInflater类实例的cloneInContext(Context newContext)方法,然后再将结果返回。而这个LayoutInflater类实例从上面的分析知道,它实际是一个PhoneLayoutInflater实例。
看一下PhoneLayoutInflater类的cloneInContext(Context newContext):
public LayoutInflater cloneInContext(Context newContext) {
return new PhoneLayoutInflater(this, newContext);
}
protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
super(original, newContext);
}
接着又调用LayoutInflater 类的构造函数:
protected LayoutInflater(LayoutInflater original, Context newContext) {
StrictMode.assertConfigurationContext(newContext, "LayoutInflater");
mContext = newContext;
mFactory = original.mFactory;
mFactory2 = original.mFactory2;
mPrivateFactory = original.mPrivateFactory;
setFilter(original.mFilter);
initPrecompiledViews();
}
这块主要是新生成一个PhoneLayoutInflater类对象,将新对象的成员变量mContext 指向cloneInContext(Context newContext)方法参数里的newContext 。PhoneLayoutInflater类对象没设置mFactory,mFactory2、mPrivateFactory、mFilter。
分析完这些代码之后,我们发现其主要就是通过加锁机制,然后通过new PhoneLayoutInflater(),得到了一个PhoneLayoutInflater实例。为啥,要整的像上面这样似的还先注册,然后设计接口,再实现,整的挺复杂。其实不止LayoutInflater实例,是这样实现的。像其他的ActivityManager、ActivityTaskManager、AccessibilityManager等实例都是通过类似这样的一种方式实现的。这样就通过设计形式,将这些实例的获取方式统一了起来。这也是值得我们学习的。