读书笔记-Android开发艺术探索-第12章-Bitmap的加载和Cache

1.Bitmap的高效加载

BitmapFactory类提供了四类方法:decodeFile,decodeResource,decodeStream和decodeByteArray,分别用于支持从文件系统,资源,输入流以及字节数组中加载出一个Bitmap对象,其中decodeFile和decodeResource又间接调用了decodeStream方法,这四类方法最终是在Android的底层实现的。

BitmapFactory.Options用来对图片进行采样缩放。
inSampleSize参数,即采样率,取值n应该总是2的指数(1,2,4,8…),采样后图片的宽/高均为原图大小的1/n。
inJustDecodeBounds参数,设置为true时,BitmapFactory只会解析图片的原始宽/高信息,并不会去真正地加载图片,所以这个操作是轻量级的。需要注意的是,这个时候BitmapFactory获取的图片宽高信息和图片的位置以及程序运行的设备有关,这都可能导致BitmapFactory获取到不同的结果。

获取采样率:

public static Bitmap decodeBmpFromRes(Resources res, int resId, int reqWidth, int reqHeight) {
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    final int width = options.outWidth;
    final int height = options.outHeight;
    int inSampleSize = 1;

    if (width > reqWidth || height > reqHeight) {
        final int halfWidth = width / 2;
        final int halfHeight = height / 2;
        while ((halfWidth / inSampleSize) >= reqWidth && (halfWidth / inSampleSize) >= reqHeight) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

mImageView.setImageBitmap(decodeBmpFromRes(getResource(), R.id.myimage, 100, 100));

2.Android中的缓存策略

LRU(Least Recently Used),近期最少使用算法,其核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。

1.LruCache-内存缓存

LruCache是一个线程安全的泛型类,它内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,其提供了get和put方法来完成缓存的获取和添加操作,当缓存满时,LruCache会移除较早使用的缓存对象,然后再添加新的缓存对象。

强引用:直接的对象引用。
软引用:当一个对象只有软引用存在时,系统内存不足时此对象会被gc回收。
弱引用:当一个对象只有弱引用存在时,次对象会随时被gc回收。

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);

2.DiskLruCache-存储设备缓存

1.DiskLruCache的创建
DiskLruCache并不能通过构造方法来创建,它提供了open方法用于创建自身,如下:

// derectory:表示磁盘缓存在文件系统中的存储路径。
// appVersion:表示应用的版本号,一般设为1即可。
// valueCount:表示单个节点所对应的数据的个数,一般设为1即可。
// maxSize:表示缓存的总大小。
public static DiskLruCache open(File derectory, int appVersion, int valueCount, long maxSize);

典型DiskLruCache创建过程:

private static final long DISK_CACHE_SIZE = 1024 * 1024 * 50; //50M

File diskCacheDir = getDiskCacheDir(mContext, "bitmap");
if (!diskCacheDir.exists()) {
    diskCacheDir.mkdirs();
}
mDiskLruCache = DiskLruCache.open(diskCacheDir, 1, 1, DISK_CACHE_SIZE);

2.DiskLruCache的缓存添加
DiskLruCache的缓存添加的操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象。

private static final int DISK_CACHE_INDEX = 0; // valueCount的个数为1,index为0

String key = hashKeyFormUrl(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if (editor != null) {
    OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
    if (downloadUrlToStream(url, outputStream)) {
        editor.commit();
    } else {
        editor.abort();
    }
    mDiskLruCache.flush();
}

3.DiskLruCache的缓存查找
通过DiskLruCache的get方法得到一个Snapshot对象,通过Snapshot对象可得到缓存的文件输入流。

Bitmap bitmap = null;
String key = hashKeyFormUrl(url);
DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
if (snapShot != null) {
    FileInputStream fileInputStream = (FileInputStream) snapShot.getInputStream(DISK_CACHE_INDEX);
    FileDescriptor fileDescriptor = fileInputStream.getFD();
    bitmap = mImageResizer.decodeBmpFromFD(fileDescriptor, reqWidth, reqHeight);
    if (bitmap != null) {
        addBitmapToMemoryCache(key, bitmap);
    }
}

3.ImageLoader的实现

功能:图片的同步/异步加载,图片压缩,内存缓存,磁盘缓存,网络拉取。
ImageLoader.java

3.ImageLoader的使用

1.图片墙效果

MainActivity.java

2.优化列表的卡顿现象

1.不要在getView中执行耗时操作,不直接在getView中加载图片,应采用异步方式处理。
2.控制异步任务的执行频率:在列表滑动的时候停止加载图片,等列表停下来以后再加载图片。
3.在某些特殊情况下,开启硬件加速:给Activity添加配置android:hardwareAccelerated=”true”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值