您的位置:首页 > 移动开发 > Android开发

android 之加载图片(二)

2015-07-17 17:05 429 查看

android 之加载图片(二)

将单个Bitmap加载到UI是简单直接的,但是如果我们需要一次性加载大量的图片,事情则会变得复杂起来。在大多数情况下(例如在使用ListView,GridView或ViewPager时),屏幕上的图片和因滑动将要显示的图片的数量通常是没有限制的。

通过循环利用子视图可以缓解内存的使用,垃圾回收器也会释放那些不再需要使用的Bitmap。这些机制都非常好,但是为了保证一个流畅的用户体验,我们希望避免在每次屏幕滑动回来时,都要重复处理那些图片。内存与磁盘缓存通常可以起到辅助作用,允许控件可以快速地重新加载那些处理过的图片。

这一课会介绍在加载多张Bitmap时使用内存缓存与磁盘缓存来提高响应速度与UI流畅度。


使用内存缓存(Use a Memory Cache)

内存缓存以花费宝贵的程序内存为前提来快速访问位图。LruCache类(在API Level 4的Support Library中也可以找到)特别适合用来缓存Bitmaps,它使用一个强引用(strong referenced)的LinkedHashMap保存最近引用的对象,并且在缓存超出设置大小的时候剔除(evict)最近最少使用到的对象。

为了给LruCache选择一个合适的大小,需要考虑到下面一些因素:

应用剩下了多少可用的内存?
多少张图片会同时呈现到屏幕上?
设备的屏幕大小与密度是多少?
一个具有特别高密度屏幕(xhdpi)的设备,像Galaxy Nexus会比Nexus    S(hdpi)需要一个更大的缓存空间来缓存同样数量的图片。
图片被访问的频率如何?
为不同的Bitmap组设置多个LruCache对象。
某些时候保存大量低质量的Bitmap会非常有用,加载更高质量图片的任务可以交给另外一个后台线程。

通常没有指定的大小或者公式能够适用于所有的情形,我们需要分析实际的使用情况后,提出一个合适的解决方案。缓存太小会导致额外的花销却没有明显的好处,缓存太大同样会导致java.lang.OutOfMemory的异常,并且使得你的程序只留下小部分的内存用来工作(缓存占用太多内存,导致其他操作会因为内存不够而抛出异常)。


下面是一个为Bitmap建立LruCache的示例

private void initLruCache() {

// 获取程序运行的最大可用内存
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

// 将程序可用内存的1/8大小分配给缓存
final int cacheSize = maxMemory / 8;

mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount() / 1024;
}
};


}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {

if (getBitmapFromMemCache(key) == null) {

mMemoryCache.put(key, bitmap);

}

}

public Bitmap getBitmapFromMemCache(String key) {

return mMemoryCache.get(key);

}

当加载Bitmap显示到ImageView 之前,会先从LruCache 中检查是否存在这个Bitmap。如果确实存在,它会立即被用来显示到ImageView上,如果没有找到,会触发一个后台线程去处理显示该Bitmap任务。


public void loadBitmap(int resId, ImageView imageView) {

// 将图片的资源id当做map的key
final String imageKey = String.valueOf(resId);

// 先到缓存中查找
final Bitmap bitmap = getBitmapFromMemCache(imageKey);

// 如果该图片已经被缓存了
if (bitmap != null) {

// 那就直接拿来用
imageView.setImageBitmap(bitmap);

// 否则,新建任务,加载图片
} else if (cancelPotentialWork(resId, imageView)) {

final BitmapWorkerTask task = new BitmapWorkerTask(imageView);

final AsyncDrawable asyncDrawable = new AsyncDrawable(
getResources(), mPlaceHolderBitmap, task);

// 你需要创建一个AsyncDrawable并且将它绑定到目标控件ImageView中:
imageView.setImageDrawable(asyncDrawable);

task.execute(resId);
}


}

使用磁盘缓存(Use a Disk Cache)

内存缓存能够提高访问最近用过的Bitmap的速度,但是我们无法保证最近访问过的Bitmap都能够保存在缓存中。像类似GridView等需要大量数据填充的控件很容易就会用尽整个内存缓存。另外,我们的应用可能会被类似打电话等行为暂停从而退到后台,一旦退到后台,应用可能会被杀死,那么内存缓存就会被销毁,里面的Bitmap也就不存在了。如果用户恢复应用的状态,那么应用就需要重新处理那些图片。
磁盘缓存可以用来保存那些已经处理过的Bitmap,它还可以减少那些不再内存缓存中的Bitmap的加载次数。当然从磁盘读取图片会比从内存要慢,而且由于磁盘读取操作时间是不可预期的,读取操作需要在后台线程中处理。
磁盘缓存最核心的类是DiskLruCache类,这是一个android系统级的类,在框架中没有。所以想使用DiskLruCache需要从android源码中寻找这个类,由于这个非常的麻烦,所以推荐大家直接使用网上开源的项目就可以了,如https://github.com/JakeWharton/DiskLruCache
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: