android 之加载图片(二)

来源:互联网 发布:搜狐邮箱 imap 端口 编辑:程序博客网 时间:2024/05/16 14:15

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的keyfinal 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
原创粉丝点击