Android的缓存机制与Bitmap的加载

    缓存策略在Android中是非常重要的,尤其是在图片加载方面有着极为重要的作用;
    
    目前比较常用到的缓存策略是LruCache和DiskLruCache;这两个都是最近最少使用算法,这种算法的核心思想是:当缓存满了的时候,回去淘汰掉最近最少使用到的缓存对象。下面来说说这两种缓存策略的用法。
    LruCache:
  LruCache常常被用作内存缓存,是一个泛型类,内部是采用一个LinkedHashMap以强引用的方式存储外界的缓存对象;LruCache的实现就是直接 new LruCache对象,需要提供缓存的容量并重写sizeOf方法。
 
 
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize){
    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }
};


    DiskLruCache:
    DiskLruCache则常常被用作存储设备缓存,就是磁盘缓存,是通过把缓存对象写入到文件系统从而实现缓存的效果。它并不能直接使用,需要自行到网上下载源码。
       DiskLruCache的创建是不能通过构造方法来创建的,但是它提供了 open 方法用于创建,如下创建代码实现:
 
  
//获取到缓存路径,一般在/sdcard/Android/data/package_name/cache 目录下File diskCacheDir = getDiskCacheDir( mContext, "bitmap") ;if (!diskCacheDir.exists()) { //如果不存在,就创建一个目录 diskCacheDir.mkdirs() ;} //判断磁盘可用空间是否足够,足够则创建一个DiskLruCache对象if (getUsableSpace(diskCacheDir) > CACHE_SIZE) { try { mDiskLruCache = DiskLruCache. open(diskCacheDir , 1, 1, DISK_CACHE_SIZE) ; } catch (IOException e) { e.printStackTrace() ; }}

讲完了Android常用的两种缓存策略,再来讲讲Bitmap的加载问题。
    在Android中,加载一个Bitmap是通过BitmapFactory类来实现的,BitmapFactory类提供了4中方法:decodeFile、decodeResource、decodeStream和decodeByteArray,分别用于支持从文件、资源、输入流和字节数组中加载一个Bitmap。
    那在Android中,我们如何高效的加载Bitmap呢?
    主要是通过 BitmapFactory.Options 来实现,主要用到它的 inSampleSize 参数,即采样率。当 inSampleSize 值为1的时候,采样后的图片大小与原始图片大小一样;当值为2时,采样后的图片大小为原始图片大小的 1/2 * 1/2 = 1/4 ;所以关键就是来根据相应的算法来算出 inSmapleSize 的值得大小即可;
    获取 inSampleSize 的值得流程:
    
public Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeigth) {
    final BitmapFactory.Options options = new BitmapFactory.Options();

    // inJustDecodeBounds = true 时,BitmapFactory只会去加载图片原始的宽和高,
    //并不会真正的加载图片
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    //计算出 inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeigth);
    
    options.inJustDecodeBounds = false;

    return BitmapFactory.decodeResource(res, resId, options);
}

private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeigth) {
    int inSampleSize = 1;

    if (reqHeigth == 0 || reqWidth == 0) {
        return inSampleSize;
    }

    final int width = options.outWidth;
    final int heigth = options.outHeight;

    if (width > reqWidth || heigth > reqHeigth) {
        final int halfWidth = width/2;
        final int halfHeigth = heigth/2;
        while ((halfWidth / inSampleSize) > reqWidth && (halfHeigth / inSampleSize) > reqHeigth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

这样,采样率的值就可以得到了。

接下来,再来讲讲怎么去优化 Listview.

1、首先,不要在Adapter的getView中进行耗时操作,加载图片用异步的方法进行加载图片;然后,就是ListView的Item复用;
2、在ListView上下滚动的时候,停止加载图片;等到滚动停止的时候,再来加载图片。可以给ListView设置 setOnScrollListener ,并在 OnScrollListener 的 onScrollStateChanged 方法中判断列表是否处于滑动状态;
3、可以开启硬件加速:通过设置 android:hardwareAccelerated="true";


记录学习Android缓存机制过程中,遇到的问题:

1、imageView.setTag(tag, uri) 提示tag必须为resource ID
    解决办法:在strings.xml文件中创建一个item,name为TAG,然后再定义一个tag = R.id.TAG,这样就不会报错了。
2、再strings.xml文件中添加 item后,点击AS运行时,会报错,提示说resource id 在两个文件夹中不一致
    解决办法:点击菜单上的 build ,选择 Rebuild Project 重新编译,再运行就没问题了。
备注:本文主要是个人通过 Android 开发艺术探索 的学习记录,如有不对,还望更正。非常感谢! 
 


猜你喜欢

转载自blog.csdn.net/u013163331/article/details/80064753