Universal-Image-Loader(简称UIL),是一个开源的图片加载框架,该项目的目的是提供一个可复用的、灵活的、可定制的、异步图像加载,缓存和显示。
我们在进行Android应用程序开发时,图片的加载是一个绕不过去的问题,诸如加载慢导致界面卡顿或界面闪烁,图片加载失败的处理,大图片加载问题,OOM问题,图片加载导致的用用程序无响应。
使用Universal-Image-Loader,可以大大简化开发流程,而且,能够在很大程度上避免上述问题的发生。
Universal-Image-Loader 在git上的地址:
作为一个使用比较广泛,相对成熟的开源项目,Universal-Image-Loader具有如下特点:
(1)多级缓存策略,包括内存缓存策略,硬盘缓存策略(文件系统缓存或者SD卡缓存),网络下载;
(2)可配置;
(3)多线程图片下载(同步或者异步);
(4)自定义配置ImageLoader,例如线程池,图片下载器,内存缓存策略,硬盘缓存策略,图片显示选项以及其他的一些配置;
(5)图片下载过程的监听(包括图片下载进度监听);
(6)支持例如ListView,GridView进行滑动的时候暂停或者恢复图片加载显示等功能;
(7)可以根据控件(ImageView)的大小对Bitmap进行裁剪,降低Bitmap占用过多的内存;
(8)较好的控制图片的载入过程。比如暂停图片载入,又一次開始载入图片,一般使用在ListView,GridView中。滑动过程中暂停载入图片,停止滑动的时候去载入图片;
(9)提供在较慢的网络下对图片进行载入。
3 Universal-Image-Loader的使用:
(1)配置:ImageLoaderConfiguration类
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 - 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();
说明:
memoryCacheExtraOptions :maxwidth, max height,缓存文件的最大长宽 ;
threadPoolSize:线程池内数量;
memoryCache(new LruMemoryCache(2 * 1024 * 1024)):使用LruMemoryCache缓存机制;
diskCacheSize(50 * 1024 * 1024):diskCache缓存的大小;
discCacheFileCount(100):缓存的文件数量;
imageDownloader:图片下载器;
defaultDisplayImageOptions: 缺省的要显示的图片的配置;
build:开始创建
(2)ImageLoader的实例化:
ImageLoader.getInstance().init(config);
说明:
很显然,ImageLoader采用单例模式
(3)DisplayImageOptions选项的配置:
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.ic_stub) //载入图片时的图片
.showImageForEmptyUri(R.drawable.ic_empty) //没有图片资源时的默认图片
.showImageOnFail(R.drawable.ic_error) //载入失败时的图片
.cacheInMemory(true) //启用内存缓存
.cacheOnDisk(true) //启用外存缓存
.considerExifParams(true) //启用EXIF和JPEG图像格式
.displayer(new RoundedBitmapDisplayer(20)) //设置显示风格这里是圆角矩形
.build();
(4) imageLoader.displayImage方法的调用:
包括图片载入监听器接口的实现(可以采用内部匿名对象来实现);
代码如下:
this.imageLoad.displayImage(this.imageUrls[position],
holder.imageView, options,
new SimpleImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
holder.progressBar.setProgress(0);
holder.progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
holder.progressBar.setVisibility(View.GONE);
}
@Override
public void onLoadingComplete(String imageUri,
View view, Bitmap loadedImage) {
holder.progressBar.setVisibility(View.GONE);
}
}, new ImageLoadingProgressListener() {
@Override
public void onProgressUpdate(String imageUri,
View view, int current, int total) {
holder.progressBar.setProgress(Math.round(100.0f
* current / total));
}
});
说明:
需要实现图片加载监听器接口。这里,使用SimpleImageLoadingListener类来实现。
(1)onLoadingStarted:当开始加载时的操作;
(2)onLoadingFailed:Loading失败;
(3)ImageLoadingProgressListener:加载进度的监听器。
代码如下:
BaseActivity:
public class BaseActivity extends Activity {
ImageLoader imageLoader;
@Override
protected void onCreate(Bundle savedInstanceState) {
// Create global configuration and initialize ImageLoader with this configuration
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.build();
ImageLoader.getInstance().init(config);
super.onCreate(savedInstanceState);
}
}
说明:
进行了ImageLoaderConfiguration对象的创建。
MainActivity:
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageLoader imageLoader = ImageLoader.getInstance();
GridView gridView = (GridView) this.findViewById(R.id.grdvImageWall);
gridView.setAdapter(new PhotoWallAdapter(Constants.IMAGES));
}
static class ViewHolder {
ImageView imageView;
ProgressBar progressBar;
}
public class PhotoWallAdapter extends BaseAdapter {
String[] imageUrls;
ImageLoader imageLoad;
DisplayImageOptions options;
LinearLayout gridViewItem;
public PhotoWallAdapter(String[] imageUrls) {
assert imageUrls != null;
this.imageUrls = imageUrls;
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
.considerExifParams(false) // default
.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
.bitmapConfig(Bitmap.Config.ARGB_8888) // default
.displayer(new SimpleBitmapDisplayer()) // default
.handler(new Handler()) // default
.build();
this.imageLoad = ImageLoader.getInstance();
}
@Override
public int getCount() {
return this.imageUrls.length;
}
@Override
public Object getItem(int position) {
if (position <= 0 || position >= this.imageUrls.length) {
throw new IllegalArgumentException(
"position<=0||position>=this.imageUrls.length");
}
return this.imageUrls[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 判断这个image是否已经在缓存当中,如果没有就下载
final ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
gridViewItem = (LinearLayout) getLayoutInflater().inflate(
R.layout.image_wall_item, null);
holder.imageView = (ImageView) gridViewItem
.findViewById(R.id.item_image);
holder.progressBar = (ProgressBar) gridViewItem
.findViewById(R.id.item_process);
gridViewItem.setTag(holder);
convertView = gridViewItem;
} else {
holder = (ViewHolder) gridViewItem.getTag();
}
this.imageLoad.displayImage(this.imageUrls[position],
holder.imageView, options,
new SimpleImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
holder.progressBar.setProgress(0);
holder.progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
holder.progressBar.setVisibility(View.GONE);
}
@Override
public void onLoadingComplete(String imageUri,
View view, Bitmap loadedImage) {
holder.progressBar.setVisibility(View.GONE);
}
}, new ImageLoadingProgressListener() {
@Override
public void onProgressUpdate(String imageUri,
View view, int current, int total) {
holder.progressBar.setProgress(Math.round(100.0f
* current / total));
}
}); // 通过URL判断图片是否已经下载
return convertView;
}
}
}
说明:
创建ImageLoader ;
设置事件监听器;
调用this.imageLoad.displayImage;
5 Universal-Image-Loader的使用技巧:
(1)ImageLoaderConfiguration配置的线程数小于5;
(2)DisplayImageOptions选项中配置bitmapConfig为Bitmap.Config.RGB_565,因为默认是ARGB_8888, 使用RGB_565会比使用ARGB_8888少消耗约2倍;
(3)ImageLoaderConfiguration中配置图片的内存缓存为memoryCache(new WeakMemoryCache()) 或者不使用内存缓存在DisplayImageOptions选项中设置;
(4)imageScaleType(ImageScaleType.IN_SAMPLE_INT)或者imageScaleType(ImageScaleType.EXACTLY)