在android开发过程图片加载和显示基本上是每个项目中都会包含的功能,这就导致每个项目里面ImageLoader是标配。当然我们在使用的过程中有很多牛逼的(性能好,使用简单方便)开源框架可供挑选。但是如果自己手动实现一个高效的ImageLoader那给自己的技术树里面又添加了一个靓丽的枝干。ok,接下来我们一起来分析和探讨一下高效ImageLoder的实现。
一般来说,优秀的ImageLoader都具有以下几个共性:
- 图片的同步加载
- 图片的异步加载
- 图片按需要压缩
- 内存缓存
- 磁盘缓存
- 网络拉取
- 使用方便简单
- 性能好
虽然我们可能做不到优秀,但是我们也得往这个目标和方向上使劲。所以接下来的实现中,我们也会尽力去做到这些。
前两年很多同行使用软引用和弱引用来实现图片的多级缓存,但是现在使用软引用和弱引用已经变得不再可靠,它主要存在以下几点弊端和风险 因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。
另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩。
基于这些问题和风险,我们使用在3.0以后被Android引入的LruCache来进行图片内存缓存,(这个类是3.1版本中提供的,如果你是在更早的Android版本中开发,则需要导入android-support-v4的jar包)
LruCache在处理图片释放时使用的原则是最久未使用原则,即:当LruCache内存储的图片总大小大于指定内存时,自动释放未使用时长最久的图片。ok,内存缓存就它了。
我们说过优秀ImageLoader还应该包含磁盘缓存,那么我们在磁盘缓存中我们可以考虑用最基本的文件存取来实现,因为一般来说,我们的磁盘缓存在我看来就是对我们的数据进行一下备份,方便需要的时候获取,不太需要多么优秀的算法来控制它们。但是现在业内的普遍做法是使用DisckLruCache来做磁盘缓存。好吧,虽然笔者不太清楚这样做的原理,但是我们照猫画虎,也就用这个吧。毕竟我们是奔着优秀去的,业内的一些反响比较好的图片加载框架都用的它,肯定是有使用的价值所在。
ok,分析完基本的技术选型,我们开始进入框架编写的正题。
我们先从调用开始讲起,我们这边提供两种调用的方式:同步调用和异步异步调用,我们把这两个方法定义如下。
/**
* 图片异步加载
*/
public void bind(String resource,ImageView imageView,int reqWidth,int reqHeight){
}
/**
*图片同步加载
*/
public Bitmap load(String resource,int reqWidth,int reqHeight){
Bitmap bitmap = null;
return bitmap;
}
两种加载方式的实现,我们接下来一步一步地写。图片使用和加载的效率有高到低的顺序为:内存缓存 >SD卡缓存>网络请求
ok,接下来我们对内存缓存和SD卡缓存进行初始化配置。在这里我们提供一个ImgLoaderConfig来设置相关配置,这个主要包括以下几个属性(需要的话再进行进一步扩展):
/**
* 内存缓存大小
*/
private int memoryCacheSize;
/**
* SD卡缓存大小
*/
private long diskCacheSize;
/**
* SD卡缓存路径
*/
private String diskCachePath;
好了,有个这个配置类,我们可以编写我们的初始化配置方法了:
/**
* 初始化方法
*
* @param config 图片加载框架相关配置
* @param context 上下文
*/
public void init(ImgLoaderConfig config, Context context) {
if (null == context) {
throw new IllegalArgumentException("the context could not is null");
}
if (config.getMemoryCacheSize() <= 0) {
int maxMemory = (int) Runtime.getRuntime().maxMemory() / 1024;
memoryCacheSize = maxMemory / 8;
} else {
memoryCacheSize = config.getMemoryCacheSize();
}
if (config.getDiskCacheSize() <= 0) {
diskCacheSize = DISK_CACHE_SIZE;
} else {
diskCacheSize = config.getDiskCacheSize();
}
mMemoryCache =