Picasso源码分析(一):单例模式、建造者模式、面向接口编程
Picasso源码分析(二):默认的下载器、缓存、线程池和转换器
Picasso源码分析(三):快照功能实现和HandlerThread的使用
Picasso源码分析(四):不变模式、建造者模式和Request的预处理
Picasso源码分析(五):into方法追本溯源和责任链模式创建BitmapHunter
Picasso源码分析(六):BitmapHunter与请求结果的处理
Picasso使用建造者设计模式,使异步网络加载图片到控件这一复杂流程可以用一条方法链搞定。典型的Picasso加载图片的使用方式如下:
Picasso.with(context).load(url).into(imageView);
传入上下文context构造获取Picasso然后异步加载图片链接获取图片最后显示在控件上,一气呵成
或者可以对加载到的图片进行尺寸压缩后再显示到控件,如下
Picasso.with(context).load(url).resize(width,height).centerInside().into(imageView);
也可以设置图片加载过程中和加载失败后的占位图
Picasso .with(context)
.load(url)
.placeholder(R.drawable.loading)
.error(R.drawable.error)
.into(imageView);
Picasso不仅使用方便,还解决一些图片加载的硬需求,如使用复杂的图片压缩转换来尽可能的减少内存消耗、自带内存和硬盘二级缓存功能和对adapter中的控件和url进行绑定防止列表滚动造成的图片错乱等。
单例模式提供了对唯一实例的受控访问,由于在系统内存中只存在一个重量级对象(Picasso就是一个重量级对象,占用较多资源,创建过程比较繁琐),因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
static volatile Picasso singleton = null;
..................................................
public static Picasso with(Context context) {
if (singleton == null) {
synchronized (Picasso.class) {
if (singleton == null) {
singleton = new Builder(context).build();
}
}
}
return singleton;
}
可见Picasso使用标准的双检锁构建线程安全的单例,注意静态属性singleton使用volatile修饰保证多线程对singleton的可见性。
建造者模式将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
按照《Effective Java》的总结: 当构造方法或者静态工厂方法中的参数过多的时候,尤其是可选参数很多时,考虑使用建造者模式。Picasso的构造器参数就比较多(10个),建造者模式使用的相当精妙。
在with方法单例获取Picasso中,可以看到Builder的build方法创建并返回了Picasso对象
singleton = new Builder(context).build();
Builder对象有7属性需要设置,分别是下载器、线程池、缓存、监听器、转换器、RequestHandler列表及Bitmap的设置
private Downloader downloader;
private ExecutorService service;
private Cache cache;
private Listener listener;
private RequestTransformer transformer;
private List requestHandlers;
private Bitmap.Config defaultBitmapConfig;
Builder的这7个属性和Picasso这7个属性是一一对应的,在最终的Builder方法中会将这些属性传入Picasso的构造函数进行创建。
对每一个属性都单独提供了有返回值的setter方法,返回this引用,这样setter方法就可以达到链式调用的目的。以下载器的设置方法为例
public Builder downloader(Downloader downloader) {
if (downloader == null) {
throw new IllegalArgumentException("Downloader must not be null.");
}
if (this.downloader != null) {
throw new IllegalStateException("Downloader already set.");
}
this.downloader = downloader;
return this;
}
首先对空指针和重复设置进行检查,检查通过后对属性进行赋值,最后返回this引用。
通过方法参数对下载器进行了依赖注入,参数的类型是Downloader接口而不是具体的实现,体现了面向接口编程的思想,这样Picasso避免了和某一个具体下载器的耦合关系,并且方便用户定义自己的下载器,只要定义的下载器实现了Downloader接口并覆写了相应的方法即可,从而使Picasso非常的灵活和方便扩展。其他几个属性的setter类似,不再赘述。
这样通过一些列的setter配置属性后,最终通过build方法创建实例
public Picasso build() {
Context context = this.context;
if (downloader == null) {
downloader = Utils.createDefaultDownloader(context);
}
if (cache == null) {
cache = new LruCache(context);
}
if (service == null) {
service = new PicassoExecutorService();
}
if (transformer == null) {
transformer = RequestTransformer.IDENTITY;
}
Stats stats = new Stats(cache);
Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);
return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
}
可见build方法对下载器、缓存、线程池和转换器进行了默认设置,之后创建了Stats对象(提供统计和快照功能),Dispatcher对象(任务分发),最后把10个属性(上下文context和Builder的7个属性加stats和dispatcher )传递给了Picasso的构造器进行构造,最后返回了构造的Picasso对象。