今天不思考人生,说说 Android 中的单例。
单例模式大概已经被网上写烂了吧?那也拦不住我在写一遍哈哈哈。但今天谈的不是单例怎么写,毕竟如何写单例网上一抓一大把,只是看看 Android 中的单例运用。
先说说单例模式运用场景,为了避免产生多个对象消耗过多的资源,或者某个对象的类型它确实只应该存在一个,那我们就会考虑使用单例模式。
单例模式可用以下方式实现:
- 饿汉模式
- 懒汉模式
- 双重检查
- 静态内部类
- 枚举
我在看书中的时候书中说到四个实现单例的关键点:
1.构造函数不对外开放, 一般为 Private;
2.通过一个静态方法或者枚举返回单例类对象;
3.确保单例类的对象有茄子有一个,尤其是在多线程中;
4.确保单例对象在反序列化时不会从构建对象。
1,2毋庸置疑,3,4是需要注意的点,在多线程中我们需要去关心我拿到的单例对象是否依然还是同一个,不过我对于反射这个也有一点的困惑,因为通过反射哪怕是私有修饰符我也可以拿到,从而使我通过私有的构造器去创建另一个该对象的实例(大概是大家不会这么做,而我只是好奇,不过反射你这是作弊啊!!!),对于第四点我不是很懂,我还在继续在网上看资料。。。
// 测试反射创建单例和单例本身
Class<Singleton> singletonClass = Singleton.class;
Constructor[] c = singletonClass.getDeclaredConstructors();
// 可以访问私有
c[0].setAccessible(true);
Singleton singleton = Singleton.getSingleton();
LoggerUtil.printGeneralLog(singleton);
try {
Singleton s = (Singleton) c[0].newInstance();
s.test();
LoggerUtil.printGeneralLog(s);
}...省略catch
通过反射创建.png
今天主要讲的是 Android 中的单例运用,我们最熟悉的应该就是 Android 中的系统服务,它就是通过注册了一系列单例服务供我们使用,那么下面我们就来看看系统服务获取和注册的代码(API 25 的源码)。
我们先来看看如何获取系统服务,在 Context 中提供了几个方法,一个是抽象的方法,通过 Context 定义好的 Sting 去获取服务,getSystemService(@ServiceName @NonNull String name),另一个是不可继承的泛型方法,final <T> T getSystemService(Class<T> serviceClass),它最后会调用 Context 中的抽象方法 String getSystemServiceName(Class<?> serviceClass)。
public final <T> T getSystemService(Class<T> serviceClass) {
// Because subclasses may override getSystemService(String) we cannot
// perform a lookup by class alone. We must first map the class to its
// service name then invoke the string-based method.
String serviceName = getSystemServiceName(serviceClass);
return serviceName != null ? (T)getSystemService(serviceName) : null;
}
因为我们看到 Context 中基本上都是抽象的方法,要去看它实现类 ContextImpl,发现管理着系统服务的类是 SystemServiceRegistry,所有服务都是在static代码块中注册的。
// Service registry information.
// This information is never changed once static initialization has completed.
// 服务会存储在两个Map中一个Class为Key,一个String为key
private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
new HashMap<Class<?>, String>();
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
// 在静态代码块中注册各种服务
static {
// 注册方法就是把服务put到上面个Map中
registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
new CachedServiceFetcher<AccessibilityManager>() {
@Override
public AccessibilityManager createService(ContextImpl ctx) {
return AccessibilityManager.getInstance(ctx);
}});
// 省略其他代码
}
我一开始以为所有系统服务全局都只存在一个,直到某一天和别人讨论后无聊打印了 LayoutInflater 的实例地址,这时候就有一点困惑,系统服务里面的单例是不是真的单例?难道不是全局就只有着一个实例。
LayoutInflater.png所以我去仔细看了 SystemServiceRegistry 里面的代码,发现了其实它里面其实分成三种类,CachedServiceFetcher 是每个 Context 中不论怎么获取都是同一个实例,而 StaticServiceFetcher 和 StaticApplicationContextServiceFetcher 都是整个应用内的单例。
/**
* 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) {
service = createService(ctx);
cache[mCacheIndex] = service;
}
return (T)service;
}
}
public abstract T createService(ContextImpl ctx);
}
/**
* Override this class when the system service does not need a ContextImpl
* and should be cached and retained process-wide.
*/
static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> {
private T mCachedInstance;
@Override
public final T getService(ContextImpl unused) {
synchronized (StaticServiceFetcher.this) {
if (mCachedInstance == null) {
mCachedInstance = createService();
}
return mCachedInstance;
}
}
public abstract T createService();
}
/**
* Like StaticServiceFetcher, creates only one instance of the service per application, but when
* creating the service for the first time, passes it the application context of the creating
* application.
*
* TODO: Delete this once its only user (ConnectivityManager) is known to work well in the
* case where multiple application components each have their own ConnectivityManager object.
*/
static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> {
private T mCachedInstance;
@Override
public final T getService(ContextImpl ctx) {
synchronized (StaticApplicationContextServiceFetcher.this) {
if (mCachedInstance == null) {
Context appContext = ctx.getApplicationContext();
// If the application context is null, we're either in the system process or
// it's the application context very early in app initialization. In both these
// cases, the passed-in ContextImpl will not be freed, so it's safe to pass it
// to the service. http://b/27532714 .
mCachedInstance = createService(appContext != null ? appContext : ctx);
}
return mCachedInstance;
}
}
public abstract T createService(Context applicationContext);
}
Android 中的系统服务虽然是也是单例,但是分上下文的单例和应用内的单例,虽然这是一个非常非常小的一个点,很有趣是不是,很多知识都是通过好奇心驱动去获取的。
网友评论