Android设计模式——单例模式

一、单例模式

1、定义

确保某一个类只有一个实例,并且自行实例化并向整个系统提供这个唯一实例。

2、在Android中的应用场景(以LayoutInflater为例)

单例模式最简单的实现方法即将类对象的构造方法私有化,使外部类无法通过构造函数初始化该类的对象,再通过一个静态方法获取一个唯一的实例。

Android中系统的核心服务如LayoutInflater都是以单例模式运行的。我们通常使用LayoutInflater.from(context)来获取LayoutInflater服务。通过查看源码我们发现在Context的功能实现类ContextImpl中,java虚拟机在第一次加载该类时,会注册包含LayoutInflater在内的一系列系统服务,并且只注册一次,然后以键值对的方式存储在HashMap中。用户只需要通过相应的键值就能获取相应的服务,从而达到单例的效果。系统核心服务以单例的形式存在,减少资源消耗。

3、在Java中的应用场景

a 数据库连接池的设计一般采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗。

b 多线程的线程池的设计一般也采用单例模式,这是由于线程池要方便对池中的线程进行控制。

c 任务管理器和回收站也是典型的单例模式,在整个系统运行过程中,回收站和任务管理器只维护一个仅有的实例。

d 网站的计数器,一般也采用单例模式,否则很难同步计数。


优点:在内存中只存在唯一的实例,较少资源损耗,同时避免多资源的多重占用。

缺点:1、单例模式一般没有接口,扩展困难。

           2、使用不当容易引起内存泄漏。

https://github.com/simple-android-framework/android_design_patterns_analysis/tree/master/singleton/mr.simple(CEO的例子)


二、避免Context相关内存泄漏

1、尽量不对Activity做长期引用。

2、改用Application的Context

一般主要原因是长生命周期的对象引用了短生命周期的对象,导致短生命周期的对象不能被GC回收产生内存泄漏。如Activity中的一个静态变量引用了Activity的Context,因为静态变量的生命周期更长(只要其所属类没有被回收就一直存在),所以当此Activity被关闭时,由于Activity仍然被引用,所以导致不能被回收。可能Activity中存在很多大的对象等,从而造成严重的内存泄露。解决方法可以将该静态变量引用的Context改成Application的Context,因为Application的Context是贯穿整个应用存在的,不受Activity的生命周期变化而变化,就不会影响Activity的正常回收。

https://blog.csdn.net/cao_dayong/article/details/64447191?locationNum=14&fps=1(三个Activity)

3、如果不能控制生命周期,应避免使用非静态内部类。因为非静态内部类会对外部类存在一个隐式的引用,其外部类在销毁之前,如果该非静态内部类的异步任务还未完成甚至该线程是永久存在的,那么将会导致外部类的资源无法正常释放。若声明为静态内部类,会持有一个对外部类的弱引用,而弱引用很容易被GC回收,这样就解决而内存泄漏问题。

三、强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)、虚引用(PhantomReference)

1、只要某个对象有强引用与之关联,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory异常也不会回收该对象。如果想中断强引用和某个对象的关联,可以显示的将引用赋值为null,这样JVM就会在合适的时间回收该对象。

2、对于软引用关联的对象,只有内存不足的时候JVM才会回收该对象。这个特性适合实现图片缓存。当一个应用需要加载大量图片时,频繁的从硬盘获取使效率低下,而一次性装入内存又造成内存溢出,因此软引用是个很好的选择。软引用可以和一个引用队列(ReferenceQueue)相结合,如果软引用对象被回收,那么这个软引用就会被加入到与之关联的引用队列中。

3、弱引用当JVM进行垃圾回收时,无论内存是否充足,都会回收弱引用对象。不过这里所说的弱引用是指只有弱引用与之关联,若是还有强引用与之关联,那么JVM也不会回收它(软引用一样)。弱引用可以和一个引用队列(ReferenceQueue)相结合,如果弱引用对象被回收,那么这个弱引用就会被加入到与之关联的引用队列中。

4、虚引用不影响对象的生命周期,即虚引用与没有与引用关联的对象一样,在任何时候都可能被GC回收。虚引用必须和一个引用队列(ReferenceQueue)相结合,如果虚引用对象被回收,那么这个虚引用就会被加入到与之关联的引用队列中。程序通过检查该对象是否加入引用队列来判断其是否即将被回收,若即将被回收,就可以执行被回收前必须执行的动作。

https://www.cnblogs.com/dolphin0520/p/3784171.html



猜你喜欢

转载自blog.csdn.net/code_kkk/article/details/80849020
今日推荐