Glide 源码初探(3.7.0)

作者: raywalker | 来源:发表于2017-04-23 23:35 被阅读0次

    1 缘起

    近期新的项目中用到了广受好评的的图片加载库 Glide,着实提升了不少开发效率。以文档中最常见的代码为例

    Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
    

    一行就能解决图片的自动加载,缓存,显示的问题。

    2 核心类

    Glide : 以单例模式提供了一种简单的静态接口,采用 RequestBuilder 来构建相关的请求。
    GlideContext : Glide中所有负载(all loads)的全局上下文,包含以及对外提供多样化注册机制,以及加载资源所需的类类型。
    Engine : 负载启动加载以及管理活动的,缓存的资源。
    RequestManager : 管理以及发起请求(request)。
    RequestTracker : 跟踪,取消,重启进行中的,已完成的,以及失败的请求。
    SingleRequest : 为一个Target加载一种Resource的请求(request)。

    3 分析

    3.1 Glide的初始化

    加载图片有着不同的使用场景,Glide利用 Facade 的模式做出了良好的封装。

    Glide.with(X) 提供的统一接口

    让我们随即进入任一实现的代码中,最后发现了Glide的初始化逻辑:

    private static volatile Glide glide;
    public static Glide get(Context context) {
        if (glide == null) {
          synchronized (Glide.class) {
            if (glide == null) {
              initGlide(context);
            }
          }
        }
        return glide;
    }
    

    是的,“未能免俗的” Glide也采用了双重检查锁定(Double-Check Locking)实现了单例模式。显而易见的是,对于整个APP来说图片加载库有一个实例就够了。

    3.2 加载相关的View dimension 的确定

    如其官方文档所述 :

    "Glide is smart enough to figure out the sizes of Views that use layout weights or match_parent as well as the sizes of those that have concrete dimensions."

    它是如何做到的?让我们追踪下本文初始位置给出的第一行示例代码的具体调用过程:

    Glide
    .with(Fragment/Activity/View)
     + RequestManager -> LifecycleListener
       + load(model)
         RequestBuilder<Drawable>.load(model)
         + loadGeneric(model)
         + into(Y target) // Y extends Target<TranscodeType>
         + into(ImageView view)
             into (a DrawableImageViewTarget ) // Y target
               buildRequest(target)
                 -buildRequestRecursive()
                   -obtainRequest()
                     -SingleRequest.obtain
               target.setRequest(request); // set as Tag for ViewTarget
               requestManager.track(target, request);
                 requestTracker.runRequest(request);
                   request.begin();
                     #SingleRequest.begin()
                         target.getSize(this);
                           // view.addPreDrawListener
                           // callback callled onSizeReady async
                         target.onLoadStarted() -> apply your placeholder
    

    原来正在发起图片请求前,有一个获取target size的异步调用。继续来看相关的ViewTargetgetSize()方法:

    ViewTarget.getSize(cb)
        sizeDeterminer.getSize(cb);
            ViewTreeObserver observer = view.getViewTreeObserver();
            layoutListener = new SizeDeterminerLayoutListener(this);
            observer.addOnPreDrawListener(layoutListener);
                onPreDraw()
                    sizeDeterminer.checkCurrentDimens();
                        // consider padding 
                        int currentWidth = getTargetWidth();
                    int currentHeight = getTargetHeight();
                        notifyCbs(currentWidth, currentHeight);
    cb.onSizeReady(width, height);
    

    此处可以发现,由于View自身会经历不同的阶段(measure - layout - draw),在当次调用时,其大小可能有不确定性。加载过程如果在view大小未确定前,会对目标View的PreDraw事件加入监听,以得到最终确定的大小。而这也为后续支持的scale type: center_crop 和 fit_center 做好了铺垫。

    3.3 对视图层生命周期的智能处理

    由于Android View层组件Fragment,Activity 有自身的生命周期,Glide如何封装生命周期的变化,动态管理请求。我们可以从 RequestManager 创建之初的设置看出一二:

    private RequestManager supportFragmentGet(Context context, FragmentManager fm,
          Fragment parentHint) {
        SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
          // TODO(b/27524013): Factor out this Glide.get() call.
          Glide glide = Glide.get(context);
          requestManager =
              factory.build(glide, current.getLifecycle(), current.getRequestManagerTreeNode());
          current.setRequestManager(requestManager);
        }
        return requestManager;
    }
    

    其中 SupportRequestManagerFragment为UI 无关的Fragment,它被创建并且添加到当前的Activity或是主Fragment之下。它与RequestManager建立关联关系并能安全的存储它。
    requestManager = factory.build(glide, current.getLifecycle(), current.getRequestManagerTreeNode());
    即将Non-UI Fragment的生命周期关联到了当前的requestManager上。所对应的是,View层上的变化onStart,onStop,onDestroy最终会映射到对request的启动,暂停以及清除。

    3.4 对于组件扩展的支持

    让我们重新关注到Glide初始化时,所做的具体事宜。

    initGlide()
        // ...
        manifestModules = new ManifestParser(applicationContext).parse();
    
        GlideBuilder builder = new GlideBuilder()
                .setRequestManagerFactory(factory);
                
        module.applyOptions(applicationContext, builder);
        annotationGeneratedModule.applyOptions(applicationContext, builder);
        
        glide = builder.build(applicationContext);
            // initialize executors, memorySizeCalculator, bitmapPool, caches
            
            // Responsible for starting loads and managing active and cached resources
            engine = new Engine()
    
            requestManagerRetriever = new RequestManagerRetriever(
                    requestManagerFactory);
            
            return new Glide(...);
               // Glide Constructor
                registry = new Registry();
                registry.register(ByteBuffer.class, new ByteBufferEncoder())
                        .register(InputStream.class, new StreamEncoder(arrayPool))
                        /* Bitmaps */
                        .append(ByteBuffer.class, Bitmap.class,
                            new ByteBufferBitmapDecoder(downsampler))
                        .append(InputStream.class, Bitmap.class,
                            new StreamBitmapDecoder(downsampler, arrayPool))
                        .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
                        //...
                glideContext = new GlideContext(...)
        
        // eg. OKHttp integration
        // registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
        for (GlideModule module : manifestModules) {
              module.applyOptions(applicationContext, builder);
        }
        
        module.registerComponents(applicationContext, glide.registry);
        annotationGeneratedModule.registerComponents(applicationContext, glide.registry);
    

    代码中的manifestModules包含了从manifest中解析得到的模块,对于模块非空的情况,这里也提供了替换的逻辑:

    module.registerComponents(applicationContext, glide.registry);
    

    以OKHttp为例,如果设置了对应的module,这将会替换Glide默认的网络模块,而采用配置的 OKHttp Client。

    4 典型的调用栈

    Glide
    .with(Fragment/Activity/View)
     + RequestManager -> LifecycleListener
       + load(model)
         RequestBuilder<Drawable>.load(model)
         + loadGeneric(model)
         + into(Y target) // Y extends Target<TranscodeType>
         + into(ImageView view)
             into (a DrawableImageViewTarget ) // Y target
               buildRequest(target)
                 -buildRequestRecursive()
                   -obtainRequest()
                     -SingleRequest.obtain
               target.setRequest(request); // set as Tag for ViewTarget
               requestManager.track(target, request);
                 requestTracker.runRequest(request);
                   request.begin();
                     # SingleRequest.begin()
                         target.getSize(this);
                           // view.addPreDrawListener
                           // callback callled onSizeReady async
                         target.onLoadStarted() -> apply your placeholder
                       
                       onSizeReady()  // req.status = Status.RUNNING;
                         Engine.load()
                           // check the cache 
                           // check the active resources
                           EngineJob<R> engineJob = engineJobFactory.build(...)
                           DecodeJob<R> decodeJob = decodeJobFactory.build(..., engineJob)
    
                           engineJob.start(decodeJob);
                             decodeJob.run() // with runReason = RunReason.INITIALIZE;
                               runWrapped()
                                 // state-machine 
                                 // INIT- {RES_CACHE} -{DATA_CACHE}-{SOURCE}|FINISHED
                                 getNextGenerator()
                                 runGenerators()
                                    reschedule() // with Stage.SOURCE // reason = RunReason.SWITCH_TO_SOURCE_SERVICE
    
                                 SourceGenerator.startNext() 
                                   loadData = helper.getLoadData().get() // ModelLoader registable ?
                                     modelLoader.buildLoadData
                                   loadData.fetcher.loadData(cb)// async
                                 SourceGenerator.onDataReady()
                             decodeJob.onDataFetcherReady()
                               decodeFromRetrievedData
                                 -decodeFromData(currentFetcher, currentData, currentDataSource);
                                    decodeFromFetcher(data, dataSource)
                                     runLoadPath()
                                       LoadPath#Resource<Transcode> load(..., new DecodeCallback(...))
                                         loadWithExceptionList()
                                           DecodePath#decode()
                                             decodeResource()
                                               decodeResourceWithList
                                                 decoder.decode(data, width, height, options);
                                           callback.onResourceDecoded
                                     onResourceDecoded()
                                       appliedTransformation.transform()
                                 -notifyEncodeAndRelease
                                    notifyComplete
                                      callback.onResourceReady(resource, dataSource)
                             engineJob.onResourceReady()
                               MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
                             handleResultOnMainThread()
                               cb.onResourceReady(engineResource, dataSource);
    
                     # SingleRequest.onResourceReady(Resource<?> resource, DataSource dataSource)
                         onResourceReady(Resource<R> resource, R result, DataSource dataSource)
                           if(!requestListener.onResourceReady())
                             target.onResourceReady(result, animation)
                               ImageViewTarget.onResourceReady()
                                 setResourceInternal()
                                   view.setImageDrawable(resource);
    

    5 框架小结

    • 封装组件的具体实现

    • 支持组件的可配置化(registry)

    • 对Application view layer的高效运用

    相关文章

      网友评论

        本文标题:Glide 源码初探(3.7.0)

        本文链接:https://www.haomeiwen.com/subject/wdvdzttx.html