设计模式-单例模式
使用单例一般目的是为了使得整个程序中只能用到这一个对象而不会重复去创建,单例的构造函数通常不对外开放,然后通过一个静态方法或者枚举将对象暴露出来
1、懒汉模式
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
这种例子只有在第一次调用getInstance时才初始化并返回实例,缺点是每次都进行同步(synchronized),造成不必要开销
2、DCL
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
相比于第一个例子,synchronized移到判断里面并且加多一个判断,第一个判断是判断instance是否存在避免不必要的同步。
第二个判断为了处理DCL失效的问题,DCL失效就是涉及到代码编译执行问题,new一个对象通常会编译成多条汇编指令,(1)给singleton分配内存,(2)调用构造函数初始化成员字段,(3)sInstance指向分配空间,执行指令顺序可能是1-2-3,或者1-3-2,如果是1-3-2执行到3的时候被切换到其他线程,此时sInstance非空,但因为没有执行到2会出错,所以就会加多一个volatile修饰保证执行顺序为1-2-3
3、静态内部类单例模式
public class Singleton{
private Singleton(){}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
private static class SingletonHolder{
private static final Singleton sInstance = new Singleton;
}
}
只有在调用getInstance的时候才会初始化静态内部类,由于Classloader的加载机制保证了唯一性(可参考),至于多线程的安全性是因为JVM已有默认的缺省同步锁。
4、枚举单例
public enum SingletonEnum{
INSTANCE;
}
枚举单例可以保证安全以及唯一性,同时它有前面三个没有的优势,就是反序列化之后仍然为同一个对象,而前面的需要通过钩子函数readResolve去杜绝单例重新生成对象
5、容器实现单例模式
public class SingletonManager{
private static Map<String,Object> objMap = new HashMap<String,Object>();
private SingletonManager(){}
public static void registerService(String key,Object instance){
if(!objMap.containKey(key)){
objMap.put(key,instance);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}
通过管理器来管理
单例的做法就是通过构造函数私有化,然后通过静态方法获取唯一的实例,这个过程中必须保证线程安全以及反序列化导致生成新的对象
Android源码中的单例模式
1、我们经常需要用到Context来获取到系统级别的服务,如WindowsManagerService、ActivityManagerService,常用到的是LIstView中getView获取context,通过LayoutInflater获取服务——context.getSystemService。
Activity入口main——创建了ActivityThread、启动消息循环、(调用attach方法通过Binder机制与ActivityManagerService通信,最终调用handleLaunchActivity)创建Activity、创建Context、将Context传递给Activity,并最终调用了onCreate方法。
其中实现Context的具体类是ContextImpl,其实现就包含了使用HashMap作为Service的容器传入其中,存取就是put与get,getSystemService就是get方法,此处用到了单例模式
2、顺带了解一下LayoutInflater
- 首先调用了一个代理类PolicyManager反射构造Policy对象,进行创建了PhoneWindow和创建了LayoutInflater
- 具体实现是在Policy中,LayoutInflater具体实现是PhoneLayoutInflater,其内部有一个OnCreateView为View添加完整路径,通过createView方法
- 具体实现完整路径的流程是在Activity中的setContentView中,最终也是调用了PhoneWindow的setContentView方法,先创建了mContentParent,在通过inflate将目标视图添加到其中,
- inflate实际上是一个xml解析器,解析不同的标签(merge、普通标签),进行不同的操作,
- 然后都会调用到createViewFromTag,判断是内置或者自定义,内置的话需要用到前面PhoneLayoutInflate的OnCreateView添加前缀,最终都是调用到createView
- createView是加载该类到虚拟机中,并获取构造函数并缓存起来,再通过构造函数创建该View的对象,最后将View返回,这就是解析单个View的过程
- 我们的视图通常是一棵树,所以采用深度优先遍历rInflate将每个View元素添加到他的parent中。