[读书笔记]《APP研发录》之App图片缓存设计

图片缓存在Android开发中十分重要,从网络获取图片、显示、回收任一环节有问题都会导致OOM。尤其是列表项,会加载大量网络上的图片。当我们快速滑动列表的时候会很卡,甚至会导致内存溢出而崩溃。

为解决上述问题,ImageLoader出现了,ImageLoader的目的是为了实现异步的网络图片加载,缓存及显示,支持多线程异步加载。

ImageLoader的原理

在显示图片的时候,它会先在内存中查找,如果没有,就去本地查找,如果还没有,就去开启一个新的线程去下载这张图片,下载成功后会把图片同时缓存到内存和本地。

基于它的原理,我们在每次退出一个页面的时候,把ImageLoader内存中的缓存全部清除,这样节省了大量内存,下次再用的时候从本地取出来就是了。ImageLoader采用的是软引用的形式,所以内存中的图片会在内存不足时被系统回收。

ImageLoader的使用

  • ImageLoaderConfiguration: 对图片缓存进行总体配置,包括内存缓存的大小,本地缓存的大小和位置、日志、下载策略(FIFO还是LIFO)等等
  • ImageLoader: 我们一般使用displayImage来把URL对应的图片显示在ImageView上。
  • DisplayImageOptions: 在每个页面需要显示图片的地方,控制如何显示的细节,比如指定下载时的默认图(包括下载中,下载失败,URL为空等),是否将缓存放到内存或本地磁盘。

1、我们新建一个Application类,在里面总体配置ImageLoader:

public class ImageCacheApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        CacheManager.getInstance().initCacheDir();

        ImageLoaderConfiguration config = 
                new ImageLoaderConfiguration.Builder(
                getApplicationContext())
                .threadPriority(Thread.NORM_PRIORITY - 2)
                .memoryCacheExtraOptions(480, 480)
                .memoryCacheSize(2 * 1024 * 1024)
                .denyCacheImageMultipleSizesInMemory()
                .discCacheFileNameGenerator(new Md5FileNameGenerator())
                .tasksProcessingOrder(QueueProcessingType.LIFO)
                .memoryCache(new WeakMemoryCache()).build();

        ImageLoader.getInstance().init(config);

    }
}

2、在使用ImageView加载图片的地方,配置当前页面的ImageLoader选项,有可能是Activity,也有可能是Adapter.

private final ArrayList cinemaList;
private final AppBaseActivity context;
private DisplayImageOptions options;
public CinemaAdapter(ArrayList cinemaList,
            AppBaseActivity context) {
        this.cinemaList = cinemaList;
        this.context = context;

        options = new DisplayImageOptions.Builder()
                .showStubImage(R.drawable.ic_launcher)
                .showImageForEmptyUri(R.drawable.ic_launcher)
                .cacheInMemory()
                .cacheOnDisc()
                .build();
    }

3、在使用ImageView加载图片的地方,使用ImageLoader:

context.imageLoader.displayImage(cinemaList.get(position)
                .getCinemaPhotoUrl(), holder.imgPhoto);

其中displayImage方法的第一个参数是图片的URL,第二个参数是ImageView控件。

一般来说,ImageLoader如果性能有问题,就和这里的配置有关,尤其是ImageLoaderConfiguration。

ImageLoader的优化
尽管ImageLoader很强大很好用,但是它会一直把图片缓存到内存中,会导致内存过高,即便图片的引用是软引用,软引用在内存不足的时候就会被GC,我们希望减少GC的次数,所以要经常手动清理ImageLoader中的缓存。

我们在AppBaseActivity中的onDesdroy方法中,执行ImageLoader中的clearMemoryCache方法以确保页面销毁时,把为了显示这个页面而增加的内存缓存清除。这样,即便到了下个页面要复用之前加载过的图片,虽然内存中没有了,根据ImageLoader的缓存策略,还是可以在本地磁盘中找到。

protected void onDestroy() {
        //回收该页面缓存在内存的图片
        imageLoader.clearMemoryCache();
        super.onDestroy();
    }

你可能感兴趣的:(读书笔记)