Picasso源码完全解析(二)--Picasso实例的创建
2017-05-16 20:53
561 查看
Picasso源码完全解析(二)--Picasso实例的创建
Picasso源码完全解析(三)--Request和Action的创建
Picasso源码完全解析(四)--Action分发和执行
Picasso源码完全解析(五)--图片的获取(BitmapHunter)
Picasso源码完全解析(六)--请求的取消、暂停、和恢复
Picasso源码完全解析(七)--
CleanupThread 取消请求
Picasso源码完全解析(二)--Picasso实例的创建
Picasso提供两种方式获得Picasso实例全局的默认实例
通过Picasso.Builder自己构建Picasso实例
由于Picasso是一个重量级的对象,它的创建涉及到很多资源和复杂的过程,比如它需要占用一部分内存作为缓存,需要开启回收线程等等,同时其销毁也比较复杂,频繁的创建和销毁其实例会带来不必要的开销,因此,Picasso维护一个全局的实例用以满足大部分需求。当这个全局单例不能满足所有需求的时候,比如自定义图片的下载、处理以及转换等,可以根据需求实现自己的Picasso实例,使用完之后及时shutDown()该实例,节约系统资源。
由于Picasso的构造比较复杂,所以,Picasso的实例化比较适合用建造者模式。
下面详细介绍几方面
使用Picasso.Builder自己构建Picasso实例
Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener, RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats, Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) { ....... }
Picasso没有对外暴露其构造函数,只能通过Picasso.Builder()建造者模式创建自己的实例。建造者模式将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。 按照《Effective Java》的总结: 当构造方法或者静态工厂方法中的参数过多的时候,尤其是可选参数很多时,考虑使用建造者模式。Picasso的构造器参数就比较多(10个),建造者模式使用的相当精妙。 我们可以看到Picasso的构造函数需要的参数特别多,因此很适合使用建造者模式。
private final Context context; private Downloader downloader; private ExecutorService service; private Cache cache; private Listener listener; private RequestTransformer transformer; private List<RequestHandler> requestHandlers; private Bitmap.Config defaultBitmapConfig; private boolean indicatorsEnabled; private boolean loggingEnabled;
可以看到Builder对象需要10个属性,这10个属性和Picasso实例的10个属性是一一对应的,同时每一个属性都对应一个setter方法并返回this,用来实现链式调用。以Downloader的设置为例:
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方法创建实例
下面看看build()方法
//2.5.2版本以前 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); } } //2.5.2版本 public Picasso build() { Context context = this.context; if (downloader == null) { downloader = new OkHttp3Downloader(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); }
可以看到默认情况下,Picasso使用LRUCache作为内存缓存,使用PicassoExecutorService线程池。
先看看PicassoExecutorService
class PicassoExecutorService extends ThreadPoolExecutor { private static final int DEFAULT_THREAD_COUNT = 3; PicassoExecutorService() { super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory()); } void adjustThreadCount(NetworkInfo info) { if (info == null || !info.isConnectedOrConnecting()) { setThreadCount(DEFAULT_THREAD_COUNT); return; } switch (info.getType()) { case ConnectivityManager.TYPE_WIFI: case ConnectivityManager.TYPE_WIMAX: case ConnectivityManager.TYPE_ETHERNET: setThreadCount(4); break; case ConnectivityManager.TYPE_MOBILE: switch (info.getSubtype()) { case TelephonyManager.NETWORK_TYPE_LTE: // 4G case TelephonyManager.NETWORK_TYPE_HSPAP: case TelephonyManager.NETWORK_TYPE_EHRPD: setThreadCount(3); break; case TelephonyManager.NETWORK_TYPE_UMTS: // 3G case TelephonyManager.NETWORK_TYPE_CDMA: case TelephonyManager.NETWORK_TYPE_EVDO_0: case TelephonyManager.NETWORK_TYPE_EVDO_A: case TelephonyManager.NETWORK_TYPE_EVDO_B: setThreadCount(2); break; case TelephonyManager.NETWORK_TYPE_GPRS: // 2G case TelephonyManager.NETWORK_TYPE_EDGE: setThreadCount(1); break; default: setThreadCount(DEFAULT_THREAD_COUNT); } break; default: setThreadCount(DEFAULT_THREAD_COUNT); } }
可以看到,PicassoExecutorService默认使用3个线程作为下载线程,同时可以根据网络状况调整工作线程的数量。
2.5.2版本开始,Picasso使用OkHttp3进行下载,磁盘缓存交给OkHttp实现,2.5.2以前有所不一样,看看Utils.createDefaultDownloader(context):
static Downloader createDefaultDownloader(Context context) { if (SDK_INT >= GINGERBREAD) { try { Class.forName("okhttp3.OkHttpClient"); return OkHttp3DownloaderCreator.create(context); } catch (ClassNotFoundException ignored) { } try { Class.forName("com.squareup.okhttp.OkHttpClient"); return OkHttpDownloaderCreator.create(context); } catch (ClassNotFoundException ignored) { } } return new UrlConnectionDownloader(context); }
可以看出,2.5.2之前,如果应用集成了OkHttp,那么就使用OkHttp进行下载,磁盘缓存交给OkHttp实现,如果没有集成,就使用UrlConnectionDownloader进行下载。
Picasso没有实现磁盘缓存,磁盘缓存交给DowLoader实现。
使用默认的全局Picasso实例
通过with()方法,可以获取全局的Picasso实例:public static Picasso with(@NonNull Context context) { if (context == null) { throw new IllegalArgumentException("context == null"); } if (singleton == null) { synchronized (Picasso.class) { if (singleton == null) { singleton = new Builder(context).build(); } } } return singleton; }
Picasso使用标准的双检锁构建线程安全的全局实例,注意静态属性singleton使用volatile修饰保证多线程对singleton的可见性。
可以看出,默认情况下全局实例使用的是默认配置,大多数情况下,该实例能够满足绝大多数的需求,如果不能,可以通过自己实例化Picasso实例并通过setSingletonInstance()设置为单例,但是该方法的调用一定要在所有with()方法调用之前。
相关文章推荐
- Picasso源码完全解析(三)--Request和Action的创建
- Picasso源码完全解析(五)--图片的获取(BitmapHunter)
- Picasso源码完全解析
- Picasso源码完全解析(六)--请求的取消、暂停、和恢复
- Picasso源码完全解析(一)--概述
- Android 图片加载框架Picasso基本使用和源码完全解析
- Spring源码解析(七)——实例创建(中)
- Spring源码解析:Bean实例的创建与初始化
- Spring源码解析(八)——实例创建(下)
- Picasso源码完全解析(七)-- CleanupThread 取消请求
- Picasso源码完全解析(四)--Action分发和执行
- Spring源码解析(六)——实例创建(上)
- Xml WebService完全实例解析(一)
- WebService完全实例解析
- Xml WebService完全实例解析(三)
- Xml WebService完全实例解析
- Xml WebService完全实例解析
- Xml WebService完全实例解析(1)
- Xml WebService完全实例解析(二)
- Xml WebService完全实例解析(一)