ImageLoaderUtil
图片加载库的封装案例
Install / Use
/learn @soulrelay/ImageLoaderUtilREADME
<font color=#C4573C size=5 face="黑体">重磅更新</font>
使用ImageLoaderUtil实现一个真正意义的图集功能,持续完善和更新中
重要的东西贴三遍!
----------------------------------分隔线---------------------------------------
<font color=#C4573C size=5 face="黑体">Use Gradle</font>
allprojects {
repositories {
jcenter()
maven {
name 'glide-snapshot'
url 'http://oss.sonatype.org/content/repositories/snapshots'
}
}
}
dependencies {
//compile project(':imagelib')
compile 'com.sus.library:imagelib:1.0.1'
}

<font color=#C4573C size=5 face="黑体">前言</font>
- 图片加载是Android开发中最最基础的功能,为了降低开发周期和难度,我们经常会选用一些图片加载的开源库
- 选取第三方SDK需要谨慎
- 二次封装
<font color=#ff9866 size=4 face="黑体">注意:所有改动更新会同步到</font>GitHub
<font color=#C4573C size=5 face="黑体">主流图片加载库的对比</font>
- 共同点
- 使用简单:一句话实现图片的获取和显示
- 可配置性高:可配置各种解码、缓存、下载机制
- 自适应程度高:根据系统性能调整配置策略(如CPU核数决定最大并发数、内存决定内存缓存大小、网络状态变化调整最大并发数)
- 多级缓存
- 支持多种数据源
- 支持多种Displayer
- 兼容性好(可以配合okhttp等库进行使用)
<font color=#ff9866 size=4 face="黑体">Android-Universal-Image-Loader</font>
- 简介 * 作者:nostra13 * 面世时间:2011 * star数(截止到发稿):14509 * https://github.com/nostra13/Android-Universal-Image-Loader
- 优点 * 支持下载进度监听(ImageLoadingListener) * 可在View滚动中暂停图片加载(PauseOnScrollListener) * 默认实现多种内存缓存算法(最大最先删除,使用最少最先删除,最近最少使用,先进先删除,当然自己也可以配置缓存算法)
- 缺点 * 从2015.11.27之后不再维护,项目中不建议使用
<font color=#ff9866 size=4 face="黑体">Picasso</font>
- 简介 * 作者:JakeWharton(Square) * 面世时间:2012 * star数(截止到发稿):12076 * https://github.com/square/picasso
- 优点 * 包较小(100k) * 取消不在视野范围内图片资源的加载 * 使用最少的内存完成复杂的图片转换 * 自动添加二级缓存 * 任务调度优先级处理 * 并发线程数根据网络类型调整 * 图片的本地缓存交给同为Square出品的okhttp处理,控制图片的过期时间
- 缺点 * 功能较为简单 * 自身无实现“本地缓存”
<font color=#ff9866 size=4 face="黑体">Glide</font>
- 简介 * 作者:Sam sjudd (Google) * 面世时间:2013 * star数(截止到发稿):12067 * https://github.com/bumptech/glide
- 优点 * 多种图片格式的缓存,适用于更多的内容表现形式(如Gif、WebP、缩略图、Video) * 生命周期集成(根据Activity或者Fragment的生命周期管理图片加载请求) * 高效处理Bitmap(bitmap的复用和主动回收,减少系统回收压力) * 高效的缓存策略,灵活(Picasso只会缓存原始尺寸的图片,Glide缓存的是多种规格),加载速度快且内存开销小(默认Bitmap格式的不同,使得内存开销是Picasso的一半)
- 缺点 * 方法较多较复杂,因为相当于在Picasso上的改进,包较大(500k),影响不是很大
<font color=#ff9866 size=4 face="黑体">Fresco</font>
- 简介 * 作者:Facebook * 面世时间:2015 * star数(截止到发稿):11235 * https://github.com/facebook/fresco
- 优点 * 最大的优势在于5.0以下(最低2.3)的bitmap加载。在5.0以下系统,Fresco将图片放到一个特别的内存区域(Ashmem区) * 大大减少OOM(在更底层的Native层对OOM进行处理,图片将不再占用App的内存) * 适用于需要高性能加载大量图片的场景
- 缺点 * 包较大(2~3M) * 用法复杂 * 底层涉及c++领域,阅读源码深入学习难度大
<font color=#C4573C size=5 face="黑体">按需选择图片加载库</font>
- 图片加载需要支持Gif,之前项目中使用的Android-Universal-Image-Loader不支持Gif且Android-Universal-Image-Loader已经停止维护,遂决定替换图片加载库
- 分析完优缺点最终选择Glide的其它理由:
- Glide是在Picasso的基础上进行改进的(支持Gif,内存开销小),虽然500k左右的包大小相对于Picasso较大,但是这个数量级的影响可以接受
- 初衷是想一直维持图片的原始ImageView,而 Fresco需要在布局文件中将图片控件声明为库中自定义的SimpleDraweeView,如果切库还需要更改组件,代价会很高
- Google推荐(亲儿子),在Google很多开源项目中广泛使用
- 但不可避免的是,Glide在使用的过程中依然存在着许多坑需要我们去填!
<font color=#C4573C size=5 face="黑体">如何更好地封装图片加载库</font>
<font color=#ff9866 size=4 face="黑体">为什么要封装?</font>
先从现在面对的情形来看,项目中使用图片加载的地方都是使用的类似下面的语句
ImageLoader.getInstance().displayImage(imageUrl, imageView,options);
然而现在ImageLoader已经停止维护且已经无法满足项目需求,我们需要替换,这时你会发现如果换库的话,所有涉及到的地方都要修改(Android-Universal-Image-Loader已经和图片加载的业务逻辑严重地耦合在一起了),工作量可见一斑,这就是不封装在切库时面临的窘境! 那怎么解决那? 计算机史上有个万能的解决方案就是,如果原有层面解决不了问题,那么就请再加一层!
/**
* Created by soulrelay on 2016/10/11 13:42.
* Class Note:
* use this class to load image,single instance
*/
public class ImageLoaderUtil {
//图片默认加载类型 以后有可能有多种类型
public static final int PIC_DEFAULT_TYPE = 0;
//图片默认加载策略 以后有可能有多种图片加载策略
public static final int LOAD_STRATEGY_DEFAULT = 0;
private static ImageLoaderUtil mInstance;
private BaseImageLoaderStrategy mStrategy;
public ImageLoaderUtil() {
mStrategy = new GlideImageLoaderStrategy();
}
//单例模式,节省资源
public static ImageLoaderUtil getInstance() {
if (mInstance == null) {
synchronized (ImageLoaderUtil.class) {
if (mInstance == null) {
mInstance = new ImageLoaderUtil();
return mInstance;
}
}
}
return mInstance;
}
/**
* 统一使用App context
* 可能带来的问题:http://stackoverflow.com/questions/31964737/glide-image-loading-with-application-context
*
* @param url
* @param placeholder
* @param imageView
*/
public void loadImage(String url, int placeholder, ImageView imageView) {
mStrategy.loadImage(imageView.getContext(), url, placeholder, imageView);
}
public void loadGifImage(String url, int placeholder, ImageView imageView) {
mStrategy.loadGifImage(url, placeholder, imageView);
}
public void loadImage(String url, ImageView imageView) {
mStrategy.loadImage(url, imageView);
}
/**
* 展示图片加载进度
*/
public void loadImageWithProgress(String url, ImageView imageView, ProgressLoadListener listener) {
mStrategy.loadImageWithProgress(url,imageView,listener);
}
public void loadGifWithProgress(String url, ImageView imageView, ProgressLoadListener listener) {
mStrategy.loadGifWithProgress(url,imageView,listener);
}
/**
* 策略模式的注入操作
*
* @param strategy
*/
public void setLoadImgStrategy(BaseImageLoaderStrategy strategy) {
mStrategy = strategy;
}
/**
* 清除图片磁盘缓存
*/
public void clearImageDiskCache(final Context context) {
mStrategy.clearImageDiskCache(context);
}
/**
* 清除图片内存缓存
*/
public void clearImageMemoryCache(Context context) {
mStrategy.clearImageMemoryCache(context);
}
/**
* 根据不同的内存状态,来响应不同的内存释放策略
*
* @param context
* @param level
*/
public void trimMemory(Context context, int level) {
mStrategy.trimMemory(context, level);
}
/**
* 清除图片所有缓存
*/
public void clearImageAllCache(Context context) {
clearImageDiskCache(context.getApplicationContext());
clearImageMemoryCache(context.getApplicationContext());
}
/**
* 获取缓存大小
*
* @return CacheSize
*/
public String getCacheSize(Context context) {
return mStrategy.getCacheSize(context);
}
}
所有需要图片显示的地方使用如下方法进行调用:
- 入口唯一,所有图片加载都在ImageLoaderUtil这一个地方统一管理,使用了单例模式(据说单元素的枚举类型已经成为实现Singleton的最佳方法,你可以试试 ),
- 高效地封装减少了切库(只需要切换图片加载策略)带来的代价,默认采用GlideImageLoaderStrategy
总结:外部表现一致,内部灵活处理原则。
/**
* 图片加载库的封装演示案例
* Created by soulrelay on 2016/12/11 19:18
*/
public class MainActivity extends AppCompatActivity {
@BindView(R.id.iv_normal)
ImageView ivNormal;
@BindView(R.id.iv_gif)
ImageView ivGif;
@BindView(R.id.iv_gif1)
ImageView ivGif1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initView();
}
private void initView() {
ImageLoaderUtil.getInstance().loadImage("http://image.sports.baofeng.com/25a3dbb0c99c5e48e52e60941ed230be", R.drawable.bg_default_video_common_small, ivNormal);
ImageLoaderUtil.getInstance().loadImage("http://image.sports.baofeng.com/19ce5d6ac3b4fff255196f200b1d3079", R.drawable.bg_default_video_common_small, ivGif);
ImageLoaderUtil.getInstance().loadGifImage("http://image.sports.baofeng.com/19ce5d6ac3b4fff255196f200b1d3079", R.drawable.bg_default_video_common_small, ivGif1);
}
}
效果图如下所示:

<font color=#ff9866 size=4 face="黑体">使用策略模式封装图片加载策略</font>
如果你对策略模式不是很熟,请先参考策略模式和状态模式 首先我们需要抽象出一个图片加载的基础接口BaseImageLoaderStrategy 基本功能主要包括
- 正常加载图片
- 针对于GIF图片的特殊加载
- 加载图片的进度回调
- 清除缓存
- 获取缓存大小等
- 其它特殊需求自己封装,最好不要破坏策略模式的整体结构
/**
* Created by soulrelay on 2016/10/11.
* Class Note:
* abstract class/interface defined to load image
* (Strategy Pattern used here)
*/
public interface BaseImageLoaderStrategy {
//无占位图
void loadImage(String url, ImageView imageView);
void loadImage(String url, int placeholder, ImageView imageView);
void loadImage(Context context, String url, int placeholder, ImageView imageView);
void loadGifImage(String url, int placeholder, ImageView imageView);
void loadImageWithProgress(String url, ImageView imageView, ProgressLoadListener listener);
void loadGifWithProgress(String url, ImageView imageView, ProgressLoadListener listener);
//清除硬盘缓存
void clearImageDiskCache(final Context context);
//清除内存缓存
void clearImageMemoryCache(Context context);
//根据不同的内存状态,来响应不同的内存释放策略
void trimMemory(Context context, int level);
//获取缓存大小
String getCacheSize(Context context);
}
需要说明的一点是:
- 当封装的方法参数比较少时可以按照上述方式进行抽象,如果需要传递的参数较多,可以考虑使用建造者模式建造者模式
- 例如封装一个ImageLoaderConfiguration,包含如下参数等等,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
- type 图片加载的
Related Skills
node-connect
334.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
82.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
334.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
82.1kCommit, push, and open a PR
