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);
这种写法,显得比较有内涵。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();
按个人喜好选取。