我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版,欢迎购买。点击进入详情
简介
目前常用的图片加载框架有Glide、Picasso等,拿Glide来说,每次使用都要Glide.with(context)写一堆配置下来。
Glide.with(mImageView.getContext()).load(path).into(mImageView);
虽然这种链式调用使用起来也方便,但是每次这么使用也感觉有些臃肿。
于是自己在项目中中进行了一些简要的封装,说封装也就是用一个工具类比如GlideUtils,里面都是一些static的方法,方法只需要传入与ImageView相关的参数即可。
但这种方法有个问题是,如果图片有变动,那就需要在GlideUtils里面新增或者修改一个方法,这样不符合开闭原则。
解决方案
我们想,图片的显示是依赖于众多的图片配置信息的,比如Url、宽高、占位符、错误图片、是否Gif等,所以我们只需要有一个图片信息的配置类,在使用的时候只需要增加或者修改图片的配置属性,就可以达到图片展示的目的。
ImageLoader就是我们封装的图片框架;
ImageOptions就是图片配置信息类;
最终实现就是交给具体的Image框架完成。
实例
- 新建一个GlideOptions类,专门用来配置Glide要求的图片参数信息:
public class GlideOptions extends BaseImageOptions {
private DiskCacheStrategy diskCacheStrategy;
private int width;
private int height;
private boolean isGif;
private GlideOptions(Builder builder) {
this.resId = builder.resId;
this.url = builder.url;
this.imageView = builder.imageView;
this.placeholder = builder.placeholder;
this.errorImage = builder.errorImage;
this.diskCacheStrategy = builder.cache;
this.width = builder.width;
this.height = builder.height;
this.isGif = builder.isGif;
}
public DiskCacheStrategy getCacheStrategy() {
return diskCacheStrategy;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public boolean isGif() {
return isGif;
}
public static Builder builder() {
return new Builder();
}
// Builder模式
public static final class Builder {
private int resId;
private String url;
private ImageView imageView;
private int placeholder;
private int errorImage;
private DiskCacheStrategy cache;
private int width;
private int height;
private boolean isGif;
private Builder() {
}
public Builder resId(int resId) {
this.resId = resId;
return this;
}
public Builder url(String url) {
this.url = url;
return this;
}
public Builder imageView(ImageView imageView) {
this.imageView = imageView;
return this;
}
public Builder placeholder(int placeholder) {
this.placeholder = placeholder;
return this;
}
public Builder errorImage(int errorImage) {
this.errorImage = errorImage;
return this;
}
public Builder cache(DiskCacheStrategy cache) {
this.cache = cache;
return this;
}
public Builder width(int width) {
this.width = width;
return this;
}
public Builder height(int height) {
this.height = height;
return this;
}
public Builder gif(boolean isGif) {
this.isGif = isGif;
return this;
}
public GlideOptions build() {
return new GlideOptions(this);
}
}
}
- 新建一个GlideManager单例类,用来加载图片:
public class GlideManager {
private static volatile GlideManager sInstance = null;
private GlideManager() {
}
public static GlideManager getInstance() {
if (sInstance == null) {
synchronized (GlideManager.class) {
if (sInstance == null) {
sInstance = new GlideManager();
}
}
}
return sInstance;
}
public void display(Context context, GlideOptions options) {
if (context != null && options != null) {
RequestManager requestManager = Glide.with(context);
DrawableTypeRequest request = getDrawableTypeRequest(options, requestManager);
// 设定图片长宽
if (options.getWidth() != 0 && options.getHeight() != 0) {
request.override(options.getWidth(), options.getHeight());
}
// 磁盘存储
if (options.getCacheStrategy() != null) {
request.diskCacheStrategy(options.getCacheStrategy());
}
// gif动画
if(options.isGif()){
request.asGif();
}
// imageView控件
if (options.getImageView() != null) {
request.into(options.getImageView());
}
}
}
private DrawableTypeRequest getDrawableTypeRequest(GlideOptions options, RequestManager requestManager) {
DrawableTypeRequest request = null;
if (!TextUtils.isEmpty(options.getUrl())) { // 网络加载
request = requestManager.load(options.getUrl());
Log.e("TAG", "getUrl : " + options.getUrl());
} else if (options.getResId() > 0) { // 本地加载
request = requestManager.load(options.getResId());
Log.e("TAG", "getResId : " + options.getResId());
}
return request;
}
}
- 使用:
GlideOptions options = GlideOptions.builder().url(url).imageView(iv).build();
GlideManager.getInstance().display(this, options);
拓展:切换图片框架
上面已经完成了对Glide的封装功能,但是如果哪一天项目中使用了其它的图片加载库,比如Picasso,或者公司中间件部门自己封装的图片加载库,那我们是不是又要重新写一套XXXOptions、XXXManager呢?
对于这种无缝切换图片框架的实现,我们想要实现的目的是,在调用方不用更改代码,只需要切换不同代码框架的配置信息即可。
通过接口,可以屏蔽这些不同。
public interface BaseStrategy<T> {
void displayImage(Context context, T options);
}
实现Glide的Strategy:
public class GlideStrategy implements BaseStrategy<GlideOptions> {
@Override
public void displayImage(Context context, GlideOptions options) {
if (context != null && options != null) {
RequestManager requestManager = Glide.with(context);
DrawableTypeRequest request = getDrawableTypeRequest(options, requestManager);
// 设定图片长宽
if (options.getWidth() != 0 && options.getHeight() != 0) {
request.override(options.getWidth(), options.getHeight());
}
// 磁盘存储
if (options.getCacheStrategy() != null) {
request.diskCacheStrategy(options.getCacheStrategy());
}
// gif动画
if (options.isGif()) {
request.asGif();
}
// imageView控件
if (options.getImageView() != null) {
request.into(options.getImageView());
}
}
}
private DrawableTypeRequest getDrawableTypeRequest(GlideOptions options, RequestManager requestManager) {
DrawableTypeRequest request = null;
if (!TextUtils.isEmpty(options.getUrl())) { // 网络加载
request = requestManager.load(options.getUrl());
Log.e("TAG", "getUrl : " + options.getUrl());
} else if (options.getResId() > 0) { // 本地加载
request = requestManager.load(options.getResId());
Log.e("TAG", "getResId : " + options.getResId());
}
return request;
}
}
实现ImageLoader,通用的图片调用类:
public class ImageLoader {
private static volatile ImageLoader sInstance = null;
private BaseStrategy strategy;
public void setStrategy(BaseStrategy strategy) {
this.strategy = strategy;
}
private ImageLoader() {
}
public static ImageLoader getInstance() {
if (sInstance == null) {
synchronized (ImageLoader.class) {
if (sInstance == null) {
sInstance = new ImageLoader();
}
}
}
return sInstance;
}
public void loadImage(Context context, BaseImageOptions options) {
if (context != null && options != null && strategy != null) {
strategy.displayImage(context, options);
}
}
}
调用方式:
ImageLoader.getInstance().setStrategy(new GlideStrategy());
GlideOptions options = GlideOptions.builder().url(url).imageView(iv).build();
ImageLoader.getInstance().loadImage(MainActivity.this, options);