您的位置:首页 > 其它

Bitmap高效加载、Cache和优化(一)

2016-09-10 21:42 316 查看
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存储缓存,咱们下一篇继续
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息