图片缓存在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<CinemaBean> cinemaList;
private final AppBaseActivity context;
private DisplayImageOptions options;
public CinemaAdapter(ArrayList<CinemaBean> 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();
}