一般来说,一个优秀的ImageLoader应该具备:图片的同步加载,图片的异步加载,图片压缩,内存缓存,硬盘缓存,网络拉取等功能.
那么,我们现在就开始来一一实现这几种功能!
图片压缩
图片压缩主要通过BitmapFactory.Options来实现,步骤:
1.将BimapFactory.Options的inJustDecodeBounds参数设置为true并加载图片(只是解析图片)
2.从BimapFactory.Options中取出图片的原始宽高信息,对应于onWidth和onHeight
3.根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize
4.将BimapFactory.Options的inJustDecodeBounds设置为false,然后重新加载.
package com.yixingu.myphotowall.myInageLoader;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.FileDescriptor;
/**
* Created by likaisong on 17-4-1.
* 图片压缩
*/
public class ImageResizer {
private static final String TAG = "ImageResizer";
public ImageResizer(){}
//压缩从资源文件中加载进来的图片
public static Bitmap decodeSampleFromResource(Resources res, int resId, int reqWidth, int reqHeight){
final BitmapFactory.Options options = new BitmapFactory.Options();
//将inJustDecodeBounds设置为true
options.inJustDecodeBounds = true;
//解析图片信息
BitmapFactory.decodeResource(res,resId,options);
//计算采样率
options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
//将inJustDecodeBounds设置为false,加载图片
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res,resId,options);
}
//压缩从文件描述符中加载进来的图片
public static Bitmap decodeSampleFromFileDescriptor(FileDescriptor fd, int reqWidth, int reqHeight){
final BitmapFactory.Options options = new BitmapFactory.Options();
//将inJustDecodeBounds设置为true
options.inJustDecodeBounds = true;
//解析图片信息
BitmapFactory.decodeFileDescriptor(fd,null,options);
//计算采样率
options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
//将inJustDecodeBounds设置为false,加载图片
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFileDescriptor(fd,null,options);
}
//计算inSampleSize
public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if(height > reqHeight || width > reqWidth){
final int halfHeight = height/2;
final int halfWidth = width/2;
while((halfHeight/inSampleSize) >= reqHeight && (halfWidth/inSampleSize) >= reqWidth){
inSampleSize *= 2;
}
}
return inSampleSize;
}
}
内存缓存和硬盘缓存的实现
主要是通过LruCache和DiskLruCache来实现
//内存添加缓存对象,主要通过put
private void addBitmaptoMemoryCache(String key , Bitmap bitmap){
if(getBitmapFromMemCache(key) == null){
mMemoryCache.put(key,bitmap);
}
}
//获取主存缓存对象,主要通过get
private Bitmap getBitmapFromMemCache(String key) {
return mMemoryCache.get(key);
}
//磁盘添加缓存对象,先将url转换为key,
// 然后获取Editor对象,
// 根据Editor对象获取文件输出流,
// 最后将文件输出流写入文件系统中时检查该文件是否存在
private Bitmap loadBitmapFromHttp(String url, int reqWidth, int reqHeight) throws IOException {
if (Looper.myLooper() == Looper.getMainLooper()) {
throw new RuntimeException("can not visit network from UI Thread.");
}
if (mDiskLruCache == null) {
return null;
}
String key = hashKeyFormUrl(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if(editor != null){
OutputStream out = editor.newOutputStream(DISK_CACHE_SIZE);
if(downloadUrlToStream(url,out)){
editor.commit();
}else{
editor.abort();
}
mDiskLruCache.flush();
}
return loadBitmaptoDiskCache(url,reqWidth,reqHeight);
}
//读