单例模式-LayoutInflater

举报
yd_221104950 发表于 2020/12/03 00:07:03 2020/12/03
【摘要】 前言 在Android系统中,我们通常会通过上下文对象Context获取一些系统级别的服务。而这些服务会在适当的时候以单例的形式注册在系统中,那么我们就可以通过Context的getSystemService(String name)获取。 以下的源码是Android8.0 API 26。 LayoutInflater 今天我们来看一下Android源码中的设计...

前言

在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); } ...
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

我们使用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;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

从上面的代码,结合我们在前言中提到的,可知,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} * ... */
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

从上面的信息,我们可以知道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(); ... }

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

我再来看看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); }
 }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

从上面的代码我们看到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); } ...
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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; } ...
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

SYSTEM_SERVICE_FETCHERS是一个HashMap:

private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS = new HashMap<String, ServiceFetcher<?>>();

  
 
  • 1
  • 2

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; }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

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); }


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

至此,我们终于从SystemServiceRegistry对象中把LayoutInflater单例取回来了。
核心服务以单例形式存在,减少了资源的消耗。

谢谢

文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_40763897/article/details/103841322

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。