Bitmap加载
BitmapFactory提供了四类方法:decodeFile,decodeResource,decodeStream,decodeByteArray,分别用于支持从文件系统,资源,输入流以及字节数组中加载一个Bitmap对象。
采用BitmapFactory.Options缩放图片可以高效加载Bitmap,其inSampleSize参数即采样率
获取采样率?
1.将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片
2.从BitmapFactory.Options中取出图片的原始宽高信息,他们对应于outWidth和outHeight参数
3.根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize
4.将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片。
public static Bitmap decodeSamledBitmapFromResource(Resource res,int resId,int reqWidth,int reqHeight) {
// First decode with inJustDecodeBounds = true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res,resId,options);
// calculate inSamleSize
options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res,resId,options);
}
public static int calculateInSampleSize(
BitmapFactory.Options options,int reqWidth,int reqHeight){
//Raw height and width of image
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;
}
mImageView.setImageBitmap(decodeSamledBitmapFromResource(getResources(),R.id.myimage,100,100));
Android中的缓存策略
当程序第一次从网络加载图片后,就将其缓存到存储设备上,这样下次使用这张图片就不用从网络上获取了,节省流量;很多时候为了提高应用的用户体验,往往还会把图片在内存中再缓存一份,这样应该打算从网络上请求一张图片时程序首先会从内存中去获取,如果内存中没有那就从存储设备中获取,如果存储设备中也没有,那就从网络下载这张图片。
缓存策略主要包含缓存的添加,获取和删除这三类操作。
缓存算法LRU(Least Recently Used),LRU是近期最少使用算法,核心思想是当缓存满时,会优先淘汰那些近期使用的缓存对象。LRU算法的缓存有两种:LruCache和DiskLruCache,Lru用于实现内存缓存,而DiskLruCache实现存储设备缓存。
LruCache
强引用:直接的对象引用
软引用:但一个对象只有软引用存在时,系统内存不足时此对象会被gc回收
弱引用:当一个对象只有弱引用存在时,此对象会随时被gc回收
LruCache是一个泛型类,它内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,其提供了get和put方法来完成缓存的获取和添加操作,当缓存满时,LruCache会移除较早使用的缓存对象,然后添加新的缓存对象。LruCache是线程安全的
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String,Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key,Bitmap bitmap) {
return bitmap.getRowBytes()*bitmap.getHeight() / 1024;
}
}
//从LruCache中获取一个缓存对象
mMemoryCache.get(key)
//向LruCache中添加一个缓存对象
mMemoryCache.put(key,bitmap)
DiskLruCache
磁盘缓存,通过将缓存对象写入文件系统,从而实现缓存的效果。
DiskLruCache的创建过程
private static final long DISK_CACHE_SIZE = 1024* 1024 * 50;//50MB
File diskCacheDir = getDiskCacheDir(mContext,"bitmap");
if(!diskCacheDir.exists()) {
diskCachDir.mkdirs();
}
mDiskLruCache = DiskLruCache.open(diskCacheDir,1,1,DISK_CACHE_SIZE);
DiskLruCache的缓存添加
DiskLruCache的缓存添加的操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象;首先需要获取图片url所对应的key,然后根据key就可以通过edit()来获取Editor对象,一般采用url的MD5作为key。
private String hashKeyFormUrl(String url) {
String cacheKey;
try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(url.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch(NoSuchAlgorithmException e){
cacheKey = String.valueOf(url.hashCode());
}
return cacheKey;
}
private String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for(int i=0;i<bytes.length;i++){
String hex = Integer.toHexString(0xFF & bytes[i]);
if(hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
//将图片的url转成key以后,就可以获取Editor对象了
String key = hashKeyFormUrl(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if(editor!=null){
OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
}
ImageLoader实现
内存缓存和磁盘缓存是ImageLoader的核心,只有当这两级缓存都不可用时才需要从网络中拉取图片。
首先尝试从内存缓存中读取图片,接着尝试从磁盘缓存中读取图片,最后从网络中拉取图片。
图片压缩
内存缓存和磁盘缓存
选择线程池和Handler来提供ImageLoader的并发能力和访问UI的能力。
《Android开发艺术探讨》Bitmap的加载和Cache
网友评论