前言
在Android系统中,我们通常会通过上下文对象Context获取一些系统级别的服务。而这些服务会在适当的时候以单例的形式注册在系统中,那么我们就可以通过Context的getSystemService(String name)获取。
以下的源码是Android8.0 API 26。
LayoutInflater
今天我们来看一下Android源码中的设计模式之单例模式。我们来讲一讲我们经常用到的单例类LayoutInflater。在我们使用RecylerView时,经常会用到,我们写RecyclerView的适配器时就会用到,如:
public class RvAdapter extends RecyclerView.Adapter<RvViewHolder> {
...
@NonNull
@Override
public RvViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_item,parent,false);
return new RvViewHolder(itemView);
}
...
}
我们使用LayoutInflater.from(parent.getContext())来获取我们的LayoutInflater服务。我们来看看LayoutInflater的from方法:
/**
* Obtains the LayoutInflater from the given 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;
}
从上面的代码,结合我们在前言中提到的,可知,LayoutInflater已在某个时刻以单例的形式注册在系统中了。我们现在通过上下文对象Context去获取这个对象。那么我们去看看Context对象的getSystemService方法是如何获取系统服务的:
/**
* Interface to global information about an application environment. This is
* an abstract class whose implementation is provided by
* the Android system. It
* allows access to application-specific resources and classes, as well as
* up-calls for application-level operations such as launching activities,
* broadcasting and receiving intents, etc.
*/
public abstract class Context {
public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
/**
* Return the handle to a system-level service by class.
* <p>
* Currently available classes are:
* {@link android.view.LayoutInflater}
* ...
*/
}
从上面的信息,我们可以知道Context是一个抽象类,它的实现是由Android系统提供的。Context提供了关于应用环境的全局信息的接口,即我们可以通过Context提供的接口获取关于应用的全局信息。我们看看Android系统对Context的实现,如果想知道Context的实现类,我们就要找到Context在哪里被初始化,我们可以从Activity的初始化开始查找,一个Activity的入口是ActivityThread的main函数:
ActivityThread对象管理应用进程的主线程的执行,如计划和执行activity、广播和其他activity管理者请求的操作。
/**
* This manages the execution of the main thread in an
* application process, scheduling and executing activities,
* broadcasts, and other operations on it as the activity
* manager requests.
*
* {@hide}
*/
public final class ActivityThread extends ClientTransactionHandler {
public static void main(String[] args) {
...
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself.
* 将当前线程初始化为一个循环,作为应用程序的主循环,这个主循环是Android环境创建,我
* 们不能亲自去调用这个prepareMainLooper方法
*/
Looper.prepareMainLooper();
...
/**
* 创建ActivityThread对象
*/
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
/**
* 初始化主线程的Handler
*/
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
...
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
* 在这个线程运行消息队列
*/
Looper.loop();
...
}
}
我再来看看thread.attach()这个方法:
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// Watch for getting close to heap limit.
// 监视是否接近堆的限制
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
if (dalvikUsed > ((3*dalvikMax)/4)) {
if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
+ " total=" + (runtime.totalMemory()/1024)
+ " used=" + (dalvikUsed/1024));
mSomeActivitiesChanged = false;
try {
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
} else {
// Don't set application object here -- if the system crashes,
// we can't display an alert, we just want to die die die.
android.ddm.DdmHandleAppName.setAppName("system_process",
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
// add dropbox logging to libcore
DropBox.setReporter(new DropBoxReporter());
ViewRootImpl.ConfigChangedCallback configChangedCallback
= (Configuration globalConfig) -> {
synchronized (mResourcesManager) {
// We need to apply this change to the resources immediately, because upon returning
// the view hierarchy will be informed about it.
if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
null /* compat */)) {
updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
mResourcesManager.getConfiguration().getLocales());
// This actually changed the resources! Tell everyone about it.
if (mPendingConfiguration == null
|| mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
mPendingConfiguration = globalConfig;
sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
}
}
}
};
ViewRootImpl.addConfigCallback(configChangedCallback);
}
}
从上面的代码我们看到Context的实现类,可能是ContextImpl,我们来看看ContextImpl.java:
ContextImpl为Context API的一般实现,它为Activity和其他应用组件提供了基本的上下文对象。
/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
class ContextImpl extends Context {
...
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
...
}
SystemServiceRegistry类管理所有系统服务,可以通过Context对象的getSystemService方法获得服务。
/**
* Manages all of the system services that can be returned by {@link Context#getSystemService}.
* Used by {@link ContextImpl}.
*/
final class SystemServiceRegistry {
...
/**
* Gets a system service from a given context.
*/
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
...
}
SYSTEM_SERVICE_FETCHERS是一个HashMap:
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
SystemServiceRegistry还有一段这样的代码:
/**
* Base interface for classes that fetch services.
* These objects must only be created during static initialization.
*/
static abstract interface ServiceFetcher<T> {
T getService(ContextImpl ctx);
}
/**
* Override this class when the system service constructor needs a
* ContextImpl and should be cached and retained by that context.
*/
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) {
try {
service = createService(ctx);
cache[mCacheIndex] = service;
} catch (ServiceNotFoundException e) {
onServiceNotFound(e);
}
}
return (T)service;
}
}
public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;
}
CachedServiceFetcher的mCacheIndex会保存单例在数组中的位置,数组的初始化也就是单例的初始化是在下面这个静态代码块里完成。
SystemServiceRegistry有一个静态块:
static {
// 注册各种各样的服务,都是单例
...
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
...
}
/**
* Statically registers a system service with the context.
* This method must be called during static initialization only.
*/
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);
}
至此,我们终于从SystemServiceRegistry对象中把LayoutInflater单例取回来了。
核心服务以单例形式存在,减少了资源的消耗。
谢谢