每日Android源码设计模式之-一、单例模式
单例设计模式是应用最广的,它必须保证一个实例,例如一个ImageLoader实例,自行实例化并且向整个系统提供这个实例。
当创建一个对象的时候消耗过多,例如要访问IO、数据库资源等时使用。
特点
1.构造函数不对外开放,private。
2.通过一个静态方法或者枚举返回单例类对象。
3.确保单例对象只有一个,特别是多线程。
4.确保在反序列化时不会重新构建对象
分为两种:
饿汉:类一创建就new对象出来。
懒汉:使用时候才去通过判断对象是否为null来new新对象。
为了保证对象唯一,有几种实现方法:
1.懒汉DCL(DoubleCheckLock)(一般能满足需求)
双重校验同步代码块方法去new对象。
缺点:
高并发下,由于不是原子操作,可能会失效,
java5以后,可以在成员变量上加上volatile来禁止该对象上的读写指令重排序。
2.静态内部类单例模式: 推荐
3.枚举单例 避免发序列化产生对象另类:容器实现单例模式
缺点:
接口扩展困难,
如果传入的是Activity的context 很可能内存泄露
4.使用容器来实现单例。
android源码中的单例模式:
我们常常通过context来获取系统级别的服务,如WindowsManagerService、ActivityManagerService等,跟常用的是LayoutInflater类。
下面来分析下LayoutInflater
LayoutInflater.form(context)获取单例->点进去也是调用了context.getSystemService(context.LAYOUT_INFLATER_SERVICE)
我们知道Activity对象和Context对象是在ActivityThread的main函数中生成的,找到main函数发现context是ComtextImpl.createActivityContext(this,r.pakageInfo,t.token)生成,然后通过activity.Attach传入Activity中的。
最后来看ComtextImpl类
这里使用的使用容器实现单例模式。
容器:private static final HashMap<String,ServiceFetcher> SYSTEM_SERVICE_MAP = new ...;
//在ComtextImpl类static代码块中,会生成各种ServiceFatcher,然后存入SYSTEM_SERVICE_MAP中。
ComtextImpl类有一个getSystemService(String name)方法用来获取存入SYSTEM_SERVICE_MAP中的ServiceFatcher对象,然后调用fetcher.getServiece(comtextImpl)方法。
fetcher中的getServiece方法从缓存ctxImpl.mServiceCache中获取对象cache.get(mContextCacheIndex)避免重复创建。
我们如何运用单例模式
例子:
ImageLoader使用DCL(Double checkLock)的方式来获取对象
public static InmageLoadegetInstance(){
if(sInstance ==null){
synchronized(ImageLoader.class){
i f(sInstance ==null){
sInstance = new ImageLoader();
}
}
}
}