关于图片库的封装相关的文章早已经看到过.图片库的封装可以使得调用者不知道,底层的具体实现,即使我们换了图片加载库,上层处的代码感知不到无需修改.
如果不做封装的话,像下面这样直接使用的话:
Glide.with(iv.getContext())
.load(carSeries.getPicurl())
.placeholder(R.drawable.ic_default_210_160)
.into(iv);
一旦你换了图片加载库,比如你想要用 Picasso ,这样涉及到图片加载的地方,你都得去改动代码,这显然是不现实的.
今天趁着有些空闲特意实践了下.知道和自己动手实践还是有差别的,更能发现一些问题.
纸上得来终觉浅 绝知此事要躬行
ImageLoader 接口定义对外调用的统一方法
public interface ImageLoader {
public void displayImage(ImageView iv, String imageUrl);
public void displayImage(ImageView iv, String imageUrl, DisplayOption option);
public static class DisplayOption {
public static final int NONE = -1;
/**
* 加载失败的资源id
*/
public int loadErrorResId = NONE;
/**
* 占位资源id
*/
public int placeHolderResId = NONE;
}
}
具体的实现类
class GlideImageLoader implements ImageLoader {
private RequestManager mRequestManager;
public GlideImageLoader(Context context) {
mRequestManager = Glide.with(context);
}
@Override
public void displayImage(ImageView iv, String imageUrl) {
displayImage(iv, imageUrl, null);
}
@Override
public void displayImage(ImageView iv, String imageUrl, DisplayOption option) {
DrawableTypeRequest drawableTypeRequest = mRequestManager.load(imageUrl);
if (option != null) {
if (option.placeHolderResId != DisplayOption.NONE && option.loadErrorResId != DisplayOption.NONE) {
drawableTypeRequest.placeholder(option.placeHolderResId)
.error(option.loadErrorResId)
.into(iv);
} else if (option.placeHolderResId != DisplayOption.NONE) {
drawableTypeRequest.placeholder(option.placeHolderResId)
.into(iv);
} else if (option.loadErrorResId != DisplayOption.NONE) {
drawableTypeRequest.error(option.placeHolderResId)
.into(iv);
}
} else {
drawableTypeRequest.into(iv);
}
}
}
统一获取实例方法
public class ImageLoaderFactory {
private static volatile ImageLoader mImageLoader;
public static void init(Context context) {
if (mImageLoader == null) {
synchronized (ImageLoaderFactory.class) {
if (mImageLoader == null) {
mImageLoader = new GlideImageLoader(context);
}
}
}
}
public static ImageLoader getInstance() {
if (mImageLoader == null) {
throw new NullPointerException("you should call method init() first in application onCreate() method");
}
return mImageLoader;
}
}
附Picasso实现:
public class PicassoImageLoader implements ImageLoader {
private Picasso mPicasso;
public PicassoImageLoader(Context context) {
mPicasso = Picasso.with(context);
}
@Override
public void displayImage(ImageView iv, String imageUrl) {
mPicasso.load(imageUrl).into(iv);
}
@Override
public void displayImage(ImageView iv, String imageUrl, DisplayOption option) {
if (option != null) {
if (option.placeHolderResId != DisplayOption.NONE && option.loadErrorResId != DisplayOption.NONE) {
mPicasso.load(imageUrl)
.placeholder(option.placeHolderResId)
.error(option.loadErrorResId)
.into(iv);
} else if (option.placeHolderResId != DisplayOption.NONE) {
mPicasso.load(imageUrl)
.placeholder(option.placeHolderResId)
.into(iv);
} else if (option.loadErrorResId != DisplayOption.NONE) {
mPicasso.load(imageUrl)
.error(option.placeHolderResId)
.into(iv);
}
}
}else{
mPicasso.load(imageUrl).into(iv);
}
}
以上其实就是策略模式的具体实践
策略模式(Strategy Pattern):定义了算法族,分别封装起来,算法族中的算法可以互相可以替换。让算法的变化独立于使用算法的客户。
ImageLoaderFactory 中的 ImageLoader 可以视为一个算法族,而 GlideImageLoader 、PicassoImageLoader 可视为具体的算法实现,他们构成了ImageLoader 这个算法族,算法互相之间可以替换。