定义
确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
使用场景
确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。例如:访问IOS和数据库等资源就要考虑使用单例模式。
单例的几种写法
第一种(懒汉, 线程不安全)
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
}
多线程下不能正常工作
第二种(懒汉线程安全)
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
}
懒汉单例模式优点在于单例只有在使用时才会被实例化,再定程度上节约了资源;缺点是第一次加载时需要及时的进行初始化,反应稍慢,还有就是每次调用getInstance()都进行同步,造成不必要的同步开销
第三种(双重校验)
public class Singleton {
private static Singleton mInstance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (mInstance == null) {
synchronized (Singleton.class) {
if (mInstance == null)
mInstance = new Singleton();
}
}
return mInstance;
}
}
双重校验的优点在于:资源利用率高,第一次执行getInstance时单例对象才会被实例化,效率高。缺点:第一次加载时反应慢,
第四种(静态内部类单例模式)
public class Singleton {
/**
* 内部类
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
静态内部类方式不仅能够确保线程安全,对象的唯一性,同时也延迟了单例的实例化。
第五种(枚举单例)
public enum Singleton {
INSTANCE;
public void doSomething() {
}
}
这种方式是Effective Java作者提倡的方式,它不仅能保证多线程同步问题,而且还能防止反序列化重现创建新的对象问题。以上几个单例写法中都会出现反序列化重新创建对象的情形。
第五种(使用容器实现单例模式)
public class Singleton {
private static Map<String, Object> objMap = new HashMap<>();
private Singleton() {
}
public static void registerService(String key, Object instance) {
if ((!objMap.containsKey(key)))
objMap.put(key, instance);
}
public static Object getService(String key) {
return objMap.get(key);
}
}
在程序初始, 将多种单例类型注入到一个统一的管理类中,在使用是根据key获取对象。这种方式使得我们可以管理多种类型的单例,并且通过统一的接口进行获取操作, 降低了用户的使用成本,也隐藏了具体的实现,降低了耦合度。
LayoutInflater中的单例应用
LayoutInflater 算是经常见的,ListView 中getView()方法中:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
view = LayoutInflater.from(mContext).inflate(R.layout.item, null);
} else {
}
return view;
}
但我们进入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;
}
这时我们看到代码调用getSystemService()方法,LayoutInflater,看getSystemService()实现
public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
从中我们看到此方法为抽象方法,Context当然也是个抽象类,so我们找到Context的实现类ContextCompl
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
这时观察看到此方法又通过SystemServiceRegistry去调用,我们继续看getSystemService源码
/**
* 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定义:
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
其实这只是个HashMap用于缓存ServiceFetcher,ServiceFetcher则保存各种Service,通过getService()方法获取系统服务,接着我们看怎么进行注册系统服务的
static {
//省略
registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
new CachedServiceFetcher<ActivityManager>() {
@Override
public ActivityManager createService(ContextImpl ctx) {
return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
}});
registerService(Context.ALARM_SERVICE, AlarmManager.class,
new CachedServiceFetcher<AlarmManager>() {
@Override
public AlarmManager createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
IAlarmManager service = IAlarmManager.Stub.asInterface(b);
return new AlarmManager(service, ctx);
}});
......
//注册LayoutInlfater
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);
}
这里则是通过静态方法注册系统服务缓存到HashMap中,这也就对接上通过getService()获取系统服务。以上就是获取LayoutInflater源码…