android 之加载图片(二)

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值