Bitmap在Android开发中经常会用到,高效加载Bitmap就显得很重要了,节省流量,加快加载速度,不出现卡顿现象这是我们想要达到的目的。
Android常用的缓存策略也是很重要的,Bitmap也需要做缓存,主要有两种,内存缓存和存储缓存,当请求加载图片时,先从内存缓存中找,找不到就到存储缓存中找,在存储缓存中也没有就从网络加载。缓存主要使用的是Lru算法,即是最近最少使用算法 ,当缓存不足的时候,会淘汰近期最少使用的缓存。常用的缓存有LruCache和DiskLruCache,LruCache用作内存缓存,DiskLruCache用作存储缓存。
一、Bitmap高效加载
加载图片,BitmapFactory有四个方法:decodeFile,decodeResource,decodeStream,decodeByteArray,分别从文件、资源、输入流、字节数组中加载Bitmap对象。
decodeFile(String PathName);//指定文件解析创建
decodeFileDescriptor(FileDescriptor fd);//从FileDescriptor解析创建Bitmap
decodeResource(Resource res,int id);//给定资源id解析创建
decodeStream(inputStream is);//从输入流中解析创建
decodeByteArray(byte[] data,int offset,int length);//从offset开始将length对象解析成Bitmap对象想要高效加载需要采用BitmapFactory.Options,通过BitmapFactory.Options可以按一定比例来加载缩小后的图片,将缩小的图片在imageView中显示,可以降低内存占用还可以避免OOM(内存溢出)。
缩放图片主要参数是inSampleSize是采样率,即是缩小多少倍,当他是大于1 的整数时才有缩小的效果,当小于等于1时,无缩小效果,例如inSampleSize == 2时,图片的长宽都缩小为原来的1/2,整个图片就相当是原来的 1/4 ,图片缩放率是 1/n 的。最新官方文档要求是inSampleSize是2的N次方,如果不是系统会选择最接近的2的N次方代替。
高效加载步骤:
1. 将BitmapFactory.Options的inJustDecodeBounds设置为true并加载图片
2.获取图片原始的宽高,对应outWidth和outHeight
3.计算inSampleSize
4.inJustDecodeBounds设置为false,重新加载该图片
inJustDecodeBounds设为true会解析图片原始宽高但是不会真正加载图片
代码是《Android开发艺术探究》中提供的
public class ImageResizer {
private static final String TAG = "ImageResizer";
public ImageResizer() {
}
public Bitmap decodeSampledBitmapFromResource(Resources 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 inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public Bitmap decodeSampledBitmapFromFileDescriptor(FileDescriptor fd, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fd, null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth,
reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFileDescriptor(fd, null, options);
}
public int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
if (reqWidth == 0 || reqHeight == 0) {
return 1;
}
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
Log.d(TAG, "origin, w= " + width + " h=" + height);
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and
// keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
Log.d(TAG, "sampleSize:" + inSampleSize);
return inSampleSize;
}
}
二、内存缓存
内存中加载图片比存储中加载要快,内存缓存提高效率节省流量
缓存包括添加、获取、修改
前面说到了内存缓存常用的策略是LruCache,这个是泛型类,内部采用的是LinkedHashMap,提供了get和put方法完成获取和添加,并且他是线程安全的
//这是LruCache定义
public class LruCache<K,V>{
private final LinkedHashMap<K,V> map;
....
}<pre name="code" class="plain">这是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;
}
};
重写sizeOf方法计算缓存对象大小,maxMemory是当前进程可用内存,一些特殊情况下还要重写entryRemoved完成资源回收工作。
获取缓存对象 mMemoryCache.get(key);
添加缓存对象 mMemoryCache.put(key,bitmap);
现在LruCache已经是源码一部分了,可直接使用
至于DiskLruCache存储缓存,咱们下一篇继续
本文探讨了在Android开发中如何高效加载Bitmap,包括使用 BitmapFactory 的方法和设置 inSampleSize 参数来实现图片缩放。同时,文章介绍了内存缓存策略,如 LruCache 的工作原理和使用,强调了内存缓存对于提升加载速度和节省流量的重要性。最后,提到了 DiskLruCache 作为存储缓存的角色,并预告了下篇将深入讨论。
1万+

被折叠的 条评论
为什么被折叠?



