先来看下它的特性:
可配置度高。支持任务线程池、下载器、解码器、内存及磁盘缓存、显示选项等等的配置。
包含内存缓存和磁盘缓存两级缓存。
支持多线程,支持异步和同步加载。
支持多种缓存算法、下载进度监听、ListView 图片错乱解决等。
首先需要在Application里面配置它的相关参数并初始化,当然你也可以不用配置直接使用默认配置:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); //创建默认的ImageLoader配置参数 ImageLoaderConfiguration configuration = ImageLoaderConfiguration .createDefault(this); //使用自定义的参数 ImageLoader.getInstance().init(configuration); } } File cacheDir = StorageUtils.getCacheDirectory(context); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) .memoryCacheExtraOptions(480, 800) // default = device screen dimensions .diskCacheExtraOptions(480, 800, CompressFormat.JPEG, 75, null) .taskExecutor(...) .taskExecutorForCachedImages(...) .threadPoolSize(3) // default .threadPriority(Thread.NORM_PRIORITY - 1) // default .tasksProcessingOrder(QueueProcessingType.FIFO) // default .denyCacheImageMultipleSizesInMemory() .memoryCache(new LruMemoryCache(2 * 1024 * 1024)) .memoryCacheSize(2 * 1024 * 1024) .memoryCacheSizePercentage(13) // default .diskCache(new UnlimitedDiscCache(cacheDir)) // default .diskCacheSize(50 * 1024 * 1024) .diskCacheFileCount(100) .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default .imageDownloader(new BaseImageDownloader(context)) // default .imageDecoder(new BaseImageDecoder()) // default .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default .writeDebugLogs() .build();
参数配置里面有很多的可配置项,比如缓存策略、加载线程池大小等,可以根据自己需求配置,这里就不一一讲解了,我们来看下调用方法,框架给我们提供了不止一种的方法来实现加载图片,下面我们来看下几个常用的方法:
final ImageView mImageView = (ImageView) findViewById(R.id.image); String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg"; ImageLoader.getInstance().loadImage(imageUrl, new ImageLoadingListener() { @Override public void onLoadingStarted(String imageUri, View view) { } @Override public void onLoadingFailed(String imageUri, View view, FailReason failReason) { } @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { mImageView.setImageBitmap(loadedImage); } @Override public void onLoadingCancelled(String imageUri, View view) { } });
该方法有两个参数,一个是url,一个是ImageLoadingListener,ImageLoadingListener回调方法有4个,图片加载开始,图片加载失败,图片加载完成,图片取消加载,我们可以根据自己的需要在对应的方法写自己的代码。当然如果你不需要这个么多方法,只需要加载完成显示,那可以传一个SimpleImageLoadingListener,他使用的是缺省适配器模式,只需要一个onLoadingComplete方法。
final ImageView mImageView = (ImageView) findViewById(R.id.image); String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg"; ImageLoader.getInstance().loadImage(imageUrl, new SimpleImageLoadingListener(){ @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { super.onLoadingComplete(imageUri, view, loadedImage); mImageView.setImageBitmap(loadedImage); } });
loadImage还有一个重载方法,可以自定义图片的大小,我们需要自己实例化一个ImageSize对象,设定图片大小传入即可。
final ImageView mImageView = (ImageView) findViewById(R.id.image); String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg"; ImageSize mImageSize = new ImageSize(100, 100); ImageLoader.getInstance().loadImage(imageUrl, mImageSize, new SimpleImageLoadingListener(){ @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { super.onLoadingComplete(imageUri, view, loadedImage); mImageView.setImageBitmap(loadedImage); } });
上面是比较简单的用法,我们平时一般需要更复杂的用法。loadImage还有一个重载方法来满足我们的需求,我们可以传入一个DisplayImageOptions来配置一些复杂的参数,比如图片加载之前显示的默认图片,加载失败显示的图片,是否缓存等。
DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.ic_stub) // resource or drawable .showImageForEmptyUri(R.drawable.ic_empty) // resource or drawable .showImageOnFail(R.drawable.ic_error) // resource or drawable .resetViewBeforeLoading(false) // default .delayBeforeLoading(1000) .cacheInMemory(false) // default .cacheOnDisk(false) // default .preProcessor(...) .postProcessor(...) .extraForDownloader(...) .considerExifParams(false) // default .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default .bitmapConfig(Bitmap.Config.ARGB_8888) // default .decodingOptions(...) .displayer(new SimpleBitmapDisplayer()) // default .handler(new Handler()) // default .build();
他的用法跟前面的用法一样,直接作为一个参数传入即可,这里就不再贴代码了。
final ImageView mImageView = (ImageView) findViewById(R.id.image); String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg"; //显示图片的配置 DisplayImageOptions options = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.ic_stub) .showImageOnFail(R.drawable.ic_error) .cacheInMemory(true) .cacheOnDisk(true) .bitmapConfig(Bitmap.Config.RGB_565) .build(); ImageLoader.getInstance().displayImage(imageUrl, mImageView, options);
通过代码可以看到,displayImage方法要简单一点,不需要传入Listener接口,只需要传入url,imageview控件,options即可。这个方法内部会对我们要显示的图片进行剪裁,返回给我们一个大小合适的图片。在图片加载过程中我们有时会需要图片加载的进度,displayImage可以传入一个ImageLoadingProgressListener()来给我们返回进度:
imageLoader.displayImage(imageUrl, mImageView, options, new SimpleImageLoadingListener(), new ImageLoadingProgressListener() { @Override public void onProgressUpdate(String imageUri, View view, int current, int total) { } });
除了加载网络图片我们还可以加载本地图片或者是assets,drawable里面的图片,这样的话我们只需要改变一下url就可以的,比如加载本地图片我们首先要知道图片的路径,然后用Scheme.FILE.wrap(path)包装一下即可,相同的assets,drawable,调用Scheme.ASSETS.wrap(path);Scheme.DRAWABLE.wrap(path),看下这个方法的源码:
/** Represents supported schemes(protocols) of URI. Provides convenient methods for work with schemes and URIs. */ public enum Scheme { HTTP("http"), HTTPS("https"), FILE("file"), CONTENT("content"), ASSETS("assets"), DRAWABLE("drawable"), UNKNOWN(""); private String scheme; private String uriPrefix; Scheme(String scheme) { this.scheme = scheme; uriPrefix = scheme + "://"; }
其实包装以后的路径添加了对应的:file://。
我们知道在listview,gridview里面的图片加载是比较常用的,我们希望在listvew或girdview滑动的时候不加载图片,等我们停下时候再加载,框架也为我们提供了这样一个监听:
listView.setOnScrollListener(new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling)); gridView.setOnScrollListener(new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling));
pauseOnScroll、pauseOnFling是boolean类型的,pauseOnScroll为true代表滑动的时候暂停加载,pauseOnFling为true代表猛的滑动过程停止加载。
框架在缓存处理上做得很到位,它的缓存分两种一种是内存缓存,一种是硬盘缓存,先来看下内存缓存。内存缓存用了LRU least recently used 近期最少使用 算法,也就是说如果缓存空间超过了我们设定的空间大小,那么框架会把近期最少用到的bitmap从缓存移除,存储的结构是基于链表结构的LinkedHashMap。当然自己也可以自定义缓存策略,在初始化配置的时候设置进去。
内存缓存用到了强引用缓存,弱引用缓存还有两者结合的缓存策略。强引用指的是如果创建了一个对象赋给了一个变量,那么这个对象永远不会被垃圾回收机制回收,及时OOM也不会回收,弱引用的对象就会被回收了。
我们来看一下强引用的LruMemoryCache,这个缓存类内部维护的是一个LinkedHashMap,我们为缓存的最大值设置了一个maxsize,缓存图片的时候我们会计算没个图片的大小,根据key判断如果已经缓存了这张照片,那么就把以前的照片移除;如果当前缓存的大小小于maxsize,则不作操作;如果大于maxsize则把第一条数据移除。
硬盘缓存有这样几个类型:
FileCountLimitedDiscCache(可以设定缓存图片的个数,当超过设定值,删除掉最先加入到硬盘的文件)
LimitedAgeDiscCache(设定文件存活的最长时间,当超过这个值,就删除该文件)
TotalSizeLimitedDiscCache(设定缓存bitmap的最大值,当超过这个值,删除最先加入到硬盘的文件)
UnlimitedDiscCache(这个缓存类没有任何的限制)
如果上面的几个不符合你的项目需求也可以自定义配置。
关于ImageLoader的学习就到这里,有时间的话看一下源码,可能会有意想不到的收获。