缓存策略在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 开发艺术探索 的学习记录,如有不对,还望更正。非常感谢!