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

本文探讨了在Android开发中如何高效加载Bitmap,包括使用 BitmapFactory 的方法和设置 inSampleSize 参数来实现图片缩放。同时,文章介绍了内存缓存策略,如 LruCache 的工作原理和使用,强调了内存缓存对于提升加载速度和节省流量的重要性。最后,提到了 DiskLruCache 作为存储缓存的角色,并预告了下篇将深入讨论。

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存储缓存,咱们下一篇继续


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值