Android-Universal-Image-Loader
官方使用介绍,参考
wiki
默认值
ImageLoaderConfiguration
全局显示选项
/* ImageLoader Configuration (ImageLoaderConfiguration) is global for application. You should set it once.
All options in Configuration builder are optional. Use only those you really want to customize.
See default values for config options in Java docs for every option.*/
// DON'T COPY THIS CODE TO YOUR PROJECT! This is just example of ALL options using.
// See the sample project how to use ImageLoader correctly.
File cacheDir = StorageUtils.getCacheDirectory(context);
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.memoryCacheExtraOptions(480, 800) // default = device screen dimensions 图片内存缓存最大宽高,默认屏幕宽高
.diskCacheExtraOptions(480, 800, null) //图片硬盘缓存最大宽高,默认屏幕宽高
.taskExecutor(...)
.taskExecutorForCachedImages(...)
.threadPoolSize(3) // default
.threadPriority(Thread.NORM_PRIORITY - 2) // default
.tasksProcessingOrder(QueueProcessingType.FIFO) // default
.denyCacheImageMultipleSizesInMemory() //默认可以内存缓存会缓存不同尺寸的同一个图片,此时使用的是FuzzyKeyMemoryCache,会使memoryCache设置无效
.memoryCache(new LruMemoryCache(2 * 1024 * 1024))
.memoryCacheSize(2 * 1024 * 1024)
.memoryCacheSizePercentage(13) // default:1/8 设置内存缓存占总内存的百分比,memoryCacheSize效果一样,使用一个就行
.diskCache(new LruDiskCache(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();
DisplayImageOptions
为每个任务设置显示选项,如果DisplayImageOptions为null,那么会使用ImageLoaderConfiguration.defaultDisplayImageOptions
/*Display Options (DisplayImageOptions) are local for every display task (ImageLoader.displayImage(...)).
Display Options can be applied to every display task (ImageLoader.displayImage(...) call).
Note: If Display Options wasn't passed to ImageLoader.displayImage(...)method then default Display Options from configuration (ImageLoaderConfiguration.defaultDisplayImageOptions(...)) will be used. */
// DON'T COPY THIS CODE TO YOUR PROJECT! This is just example of ALL options using.
// See the sample project how to use ImageLoader correctly.
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 压缩图片选项Options.inSampleSize是否用2的倍数,默认2的倍数
.bitmapConfig(Bitmap.Config.ARGB_8888) // default
.decodingOptions(...)
.displayer(new SimpleBitmapDisplayer()) // default
.handler(new Handler()) // default
.build();
UIL在listview, gridview, viewpager中的用法
//Application中定义全局的配置属性
ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)
.threadPriority(Thread.NORM_PRIORITY - 2) //设置线程优先级
.denyCacheImageMultipleSizesInMemory() //拒绝内存缓存中缓存不同size的图片
.diskCacheFileNameGenerator(new Md5FileNameGenerator()) //硬盘缓存图片文件名生成器-md5加密,默认HashCodeFileNameGenerator-hashcode
.diskCacheSize(50 * 1024 * 1024) //硬盘缓存大小50MiB,默认LruDiskCache
.tasksProcessingOrder(QueueProcessingType.LIFO) //任务后进先出,后面添加的任务先执行,多用于listview等控件,默认FIFO
.imageDownloader(new BaseImageDownloader(context,10000,20000)) //自定义图片下载器,设置10s(默认5s)连接超时,20s(默认20s)读取超时,默认5次重连
.writeDebugLogs() //打印log信息
.build(); //其它默认值看ImageLoaderConfiguration的initEmptyFieldsWithDefaultValues方法
// Initialize ImageLoader with configuration.
ImageLoader.getInstance().init(configuration);
private static class ImageAdapter extends BaseAdapter {
private static final String[] IMAGE_URLS = Constants.IMAGES;
private LayoutInflater inflater;
private DisplayImageOptions options;
ImageAdapter(Context context) {
inflater = LayoutInflater.from(context);
options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.ic_stub) //加载中的图片显示
.showImageForEmptyUri(R.drawable.ic_empty) //url为null的图片显示
.showImageOnFail(R.drawable.ic_error) //请求失败图片显示
.cacheInMemory(true) //默认false,同时使用LruMemoryCache
.cacheOnDisk(true) //默认false,同时使用LruDiskCache
.considerExifParams(true) //解码图片的时候需要考虑图片的Exif参数,有些图片自带了旋转缩放等参数
.displayer(new CircleBitmapDisplayer(Color.WHITE, 5)) //显示为圆形图片,还有其他形状的图片
.build();
}
@Override
public int getCount() {
return IMAGE_URLS.length;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
final ViewHolder holder;
if (convertView == null) {
view = inflater.inflate(R.layout.item_list_image, parent, false);
holder = new ViewHolder();
holder.text = (TextView) view.findViewById(R.id.text);
holder.image = (ImageView) view.findViewById(R.id.image);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.text.setText("Item " + (position + 1));
ImageLoader.getInstance().displayImage(IMAGE_URLS[position], holder.image, options);
return view;
}
}
static class ViewHolder {
TextView text;
ImageView image;
}
//同时注意在activity中,如果被销毁了,必须手动停止线程池,否则会造成资源的浪费
@Override
public void onDestroy() {
super.onDestroy();
ImageLoader.getInstance().stop();
}
不需要setTag,内部实现已经实现了,不会出现错乱。
pauseOnScroll
:Scroll的时候是否加载图片 pauseOnFling
:Fling是否加载图片
//onMyScrollListener如果需要自己的滚动监视器则这样使用
listView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), pauseOnScroll, pauseOnFling),onMyScrollListener);
ImageLoader是单例的,listView的滚动事件首先交给OnScrollListener来处理,onScrollStateChanged其中分别调用imageLoader.resume()恢复下载/imageLoader.pause()暂停下载来实现,如果定义了externalListener,那么就调用externalListener的onScroll/onScrollStateChanged方法.
优点
- 多线程下载图片,图片可以来源于网络,文件系统,项目文件夹assets中以及drawable中等
- 支持随意的配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置
- 支持图片的内存缓存,文件系统缓存或者SD卡缓存
- 支持图片下载过程的监听
- 根据控件(ImageView)的大小对Bitmap进行裁剪,减少Bitmap占用过多的内存
- 较好的控制图片的加载过程,例如暂停图片加载,重新开始加载图片,一般使用在ListView,GridView中,滑动过程中暂停加载图片,停止滑动的时候去加载图片
- 提供在较慢的网络下对图片进行加载
Volley并没有对imageview的大小进行匹配,而是需要自己去定义图片的显示大小好麻烦
OutOfMemoryError
虽然这个框架有很好的缓存机制,有效的避免了OOM的产生,一般的情况下产生OOM的概率比较小,但是并不能保证OutOfMemoryError永远不发生,这个框架对于OutOfMemoryError做了简单的catch,保证我们的程序遇到OOM而不被crash掉,但是如果我们使用该框架经常发生OOM,我们应该怎么去改善呢?
- 减少线程池中线程的个数,在ImageLoaderConfiguration中的(threadPoolSize)中配置,推荐配置1-5
- 在DisplayImageOptions选项中配置bitmapConfig为Bitmap.Config.RGB_565,因为默认是ARGB_8888, 使用RGB_565会比使用ARGB_8888少消耗2倍的内存
- 在ImageLoaderConfiguration中配置图片的内存缓存为memoryCache(new WeakMemoryCache()) 或者不使用内存缓存
- 在DisplayImageOptions选项中设置.imageScaleType(ImageScaleType.IN_SAMPLE_INT)或者imageScaleType(ImageScaleType.EXACTLY)
通过上面这些,相信大家对Universal-Image-Loader框架的使用已经非常的了解了,我们在使用该框架的时候尽量的使用displayImage()
方法去加载图片,loadImage()
是将图片对象回调到ImageLoadingListener接口的onLoadingComplete()方法中,需要我们手动去设置到ImageView上面,displayImage()方法中,对ImageView对象使用的是Weak references,方便垃圾回收器回收ImageView对象,如果我们要加载固定大小的图片的时候,使用loadImage()方法需要传递一个ImageSize对象,而displayImage()方法会根据ImageView对象的测量值,或者android:layout_width and android:layout_height
设定的值,或者android:maxWidth/android:maxHeight
设定的值来裁剪图片
new ImageViewAware(imageView)
.ImageViewAware内部弱引用指向imageView,这样就防止了OOM了,如果activity退出,那么发生GC,那么会回收该imageview,那么也就会回收该activity,view内部持有context引用。
简单流程
简单的讲就是ImageLoader收到加载及显示图片的任务,如果是同步的直接运行LoadAndDisplayImageTask任务,如果是异步的,那么将它交给ImageLoaderEngine线程池管理,ImageLoaderEngine分发任务到具体的线程去执行,任务实际上是通过Cache及ImageDownloader获取图片,中间可能经过BitmapProcessor和ImageDecoder处理,最终转换为Bitmap交给BitmapDisplayer在ImageAware中显示。
ImageLoaderEngine:任务分发器,负责分发LoadAndDisplayImageTask和ProcessAndDisplayImageTask给具体的线程池去执行,本文中也称其为engine
ImageAware:显示图片的对象,可以是ImageView等
ImageDownloader:图片下载器,负责从图片的各个来源获取输入流
MemoryCache:内存图片缓存,可向内存缓存缓存图片或从内存缓存读取图片
DiskCache:本地图片缓存,可向本地磁盘缓存保存图片或从本地磁盘读取图片
ImageDecoder:图片解码器,负责将图片输入流InputStream转换为Bitmap对象
BitmapProcessor:图片处理器,负责从缓存读取或写入前对图片进行处理,默认是null,如果有需求将图片设置成圆形的,可以实现该类
BitmapDisplayer:将Bitmap对象显示在相应的控件ImageAware上
LoadAndDisplayImageTask:用于加载并显示图片的任务
ProcessAndDisplayImageTask:用于处理并显示图片的任务,跟BitmapProcessor对应,必须定义了BitmapProcessor,但是内部实现其实还是使用LoadAndDisplayImageTask的
DisplayBitmapTask:用于显示图片的任务
参考
Android 开源框架Universal-Image-Loader完全解析(一)— 基本介绍及使用
Android Universal Image Loader 源码分析