本节书摘来自异步社区《Android 源码设计模式解析与实战》一书中的第2章,第2.9节运用单例模式,作者 何红辉 , 关爱民,更多章节内容可以访问云栖社区“异步社区”公众号查看
2.9 运用单例模式
在Android应用开发过程中,ImageLoader是我们最为常用的开发工具库之一。Android中最著名的ImageLoader就是Universal-Image-Loader(https://github.com/nostra13/Android-Universal-Image- Loader),它的使用过程大概是这样的:
public void initImageLoader(Context context) {
// 1. 使用Builder构建ImageLoader的配置对象
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
//加载图片的线程数
.threadPriority(Thread.NORM_PRIORITY - 2)
//解码图像的大尺寸,将在内存中缓存先前解码图像的小尺寸
.denyCacheImageMultipleSizesInMemory()
//设置磁盘缓存文件名称
.discCacheFileNameGenerator(new Md5FileNameGenerator())
//设置加载显示图片队列进程
.tasksProcessingOrder(QueueProcessingType.LIFO)
.writeDebugLogs()
.build();
// 2. 使用配置对象初始化ImageLoader
ImageLoader.getInstance().init(config);
// 3. 加载图片
ImageLoader.getInstance().displayImage("图片url", myImageView);
}
代码中出现了熟悉的getInstance()方法,因此,我们猜测这个ImageLoader使用的是单例模式。正好,小民的ImageLoader也是类似的实现,通过一个getInstance函数返回单例对象,具体代码如下:
public final class ImageLoader{
// ImageLoader实例
private static ImageLoadersInstance;
//网络请求队列
private RequestQueue mImageQueue;
// 缓存
private volatile BitmapCache mCache = new MemoryCache();
// 图片加载配置对象
private ImageLoaderConfig mConfig;
// 私有构造函数
private ImageLoader() {
}
/**
* 获取ImageLoader单例,DCL形式
* @return单例对象
*/
public static ImageLoadergetInstance() {
if (sInstance == null) {
synchronized (ImageLoader.class) {
if (sInstance == null) {
sInstance = new ImageLoader();
}
}
}
return sInstance;
}
/**通过配置类初始化ImageLoader,设置线程数量、缓存策略、加载策略等
* @param config配置对象
*/
public void init(ImageLoaderConfig config) {
mConfig = config;
mCache = mConfig.bitmapCache;
checkConfig();
mImageQueue = new RequestQueue(mConfig.threadCount);
mImageQueue.start();
}
// 代码省略
// 加载图片的接口
public void displayImage(ImageView imageView, String uri) {
displayImage(imageView, uri, null, null);
}
public void displayImage(ImageView imageView, String uri, ImageListener listener) {
displayImage(imageView, uri, null, listener);
}
public void displayImage(final ImageView imageView, final String uri,
final DisplayConfig config, final ImageListener listener) {
BitmapRequest request = new BitmapRequest(imageView, uri, config, listener);
// 加载的配置对象,如果没有设置,则使用ImageLoader的配置
request.displayConfig = request.displayConfig != null ? request.displayConfig
: mConfig.displayConfig;
// 添加到队列中
mImageQueue.addRequest(request);
}
public void stop() {
mImageQueue.stop();
}
// 图片加载Listener,加载完成后回调给客户端代码
public static interface ImageListener {
public void onComplete(ImageView imageView, Bitmap bitmap, String uri);
}
}
我们的ImageLoader类中将构造函数私有化,并且使用Double Check Lock的形式实现单例,用户通过getInstance方法获取ImageLoader单例对象。在用户使用之前需要使用ImageLoaderConfig来配置ImageLoader,配置合理的情况下才会启动用户指定数量的线程来执行图片加载请求。当用户调用displayImage方法时,ImageLoader会将请求构造成一个BitmapRequest,然后将该请求添加到请求队列中,图片加载线程(RequestDispatcher)会从请求队列(RequestQueue)中获取图片加载请求,然后加载该图片,并且将图片显示到对应的ImageView上,最后将图片缓存到缓存系统中。
在后续章节中将会阐述关于该ImageLoader的更多细节,大家可以到github(https://github.com/ bboyfeiyu/simple_imageloader)下载该库的源代码,并且结合《教你写Android ImageLoader框架》系列博文(地址为http://blog.csdn.net/column/details/android-imageloader.html)进行学习。