• glide-源码解析-1


    glide-源码解析-1

    一、前言

    Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。
    Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。
    虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。

    官方github链接地址:https://github.com/bumptech/glide
    简体中文文档:https://muyangmin.github.io/glide-docs-cn/
    本篇基于4.10.0版本做分析

    二、使用

    Glide.with(fragment).load(url).into(imageView)
    
    Glide.with(this)
    .load(url)
    .placeholder(xx)
    .error(xx)
    .override(w,h)
    .fitCenter(xx)
    .centerCrop(xx)
    .skipMemoryCache(true)
    .diskCacheStrategy(DiskCacheStrategy.NONE)
    .priority(Priority.HIGH)
    .into(imageView)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    三、主流程

    ModelLoader DataFetcher
    decode
    Transformation
    ResourceTranscoder.transcode
    Model
    Data
    Resource
    TransformedResource
    TranscodedResource
    Target

    主流程是整个glide的脉络主线,只有牢记glide主流程,才不会陷入glide细节代码中,更好理解glide

    四、with

    先从glide最简单的使用开始

    Glide.with(this).load(url).into(imageView)
    
    • 1

    image

    可以看到Glide类提供了多个静态with方法,参数类型不同而已,之所以这么做

    1. 是为了更方便的为调用者使用
    2. 是将Glide图片加载与当前组件(context, fragment, activity)绑定在一起,一当组件生命周期结束,图片加载也就停止,最大程度减少资源开销
    // Glide.java
      @NonNull
      public static RequestManager with(@NonNull Context context) {
        return getRetriever(context).get(context);
      }
      
      public static RequestManager with(@NonNull Activity activity) {
        return getRetriever(activity).get(activity);
      }
      ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    看下with(Context)方法,可以知道返回的其实是一个RequestManager类,RequestManagerRetriever类可以理解为专门生产RequestManager的类,看下它的get方法

    // RequestManagerRetriever.java
    @NonNull
      public RequestManager get(@NonNull Context context) {
        if (context == null) {
          throw new IllegalArgumentException("You cannot start a load on a null Context");
        } else if (Util.isOnMainThread() && !(context instanceof Application)) {
            
          if (context instanceof FragmentActivity) {
            return get((FragmentActivity) context);
          } else if (context instanceof Activity) {
            return get((Activity) context);
          } else if (context instanceof ContextWrapper
              // Only unwrap a ContextWrapper if the baseContext has a non-null application context.
              // Context#createPackageContext may return a Context without an Application instance,
              // in which case a ContextWrapper may be used to attach one.
              && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
            return get(((ContextWrapper) context).getBaseContext());
          }
        }
        
        // 如果传入是一个全局application,则返回的一个单例RequestManager
        return getApplicationManager(context);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    最后一句进去看下

    image

    可以看到这里面其实返回的是一个applicationManager的对象,并且是一个单例;我们可以推测这个RequestManager其实与with传入的组件生命周期管理起来,那么Glide是如何将RequestManager与activity、fragment管理起来的?我们以with(Activity为例)

    1. Glide.with(Activity)

    // RequestManagerRetriever.java
    @NonNull
    public RequestManager get(@NonNull FragmentActivity activity) {
        if (Util.isOnBackgroundThread()) {
          return get(activity.getApplicationContext());
        } else {
          assertNotDestroyed(activity);
          FragmentManager fm = activity.getSupportFragmentManager();
          return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    可以看到glide首先是判断如果是运行在后台线程,直接返回一个全局的RequestManager,否则的话,从当前activity上挂载的一个无UI界面的glideFragment中获取这个RequestManager

    @NonNull
      private RequestManager supportFragmentGet(
          @NonNull Context context,
          @NonNull FragmentManager fm,
          @Nullable Fragment parentHint,
          boolean isParentVisible) {
        SupportRequestManagerFragment current =
            getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
        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.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
          current.setRequestManager(requestManager);
        }
        return requestManager;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    可以看到glide首先从名为current的fragment获取requestManger没有就创建并存储到current中去;这里需要注意到RequestManager构造器中传入了fragment.glideLifecycle,之所以这样所是为了把拥有生命周期的fragment和RequestManager关联起来了,让RequestManager拥有感知生命周期的能力;通过上述代码我们可以简单理解一个activity对象拥有一个RequestManager(其他业务fragment暂不考虑)

    2. glide为啥要创建fragment?

    因为glide作为一个图片库,它无法感知到activity或fragment的生命周期,glide为了感知它,通过创建无UI的fragment实现了RequestManager可以监听activity、fragment生命周期;这样可以做到无侵入,且可以有效较少资源消耗

    下面的代码展示了glide是如何获取、创建、存储SupportRequestManagerFragment对象的

    @NonNull
    private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
      
        // 1. 先从fm中取fragment
        SupportRequestManagerFragment current =
            (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
        if (current == null) {
          // 2. 其次从pendingSupportRequestManagerFragments map对象中取
          current = pendingSupportRequestManagerFragments.get(fm);
          if (current == null) {
          
            // 3. 找不到就手动创建fragment
            current = new SupportRequestManagerFragment();
            current.setParentFragmentHint(parentHint);
            if (isParentVisible) {
              current.getGlideLifecycle().onStart();
            }
            
            // 4. 存储到map中
            pendingSupportRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            
            // 发送一个消息,从pendingSupportRequestManagerFragments中移除fragment
            handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
          }
        }
        return current;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    可以看到getSupportRequestManagerFragment
    先是从fm寻找,如果没有从一个pendingSupportRequestManagerFragments的map对象(key为fm)寻找,如果都没有说明fragment没有被创建过,需要手动创建,这里把fragment先存储到临时map中是因为fm存储fragment是通过消息队列方式的,不能立马从fm获取,所以pendingSupportRequestManagerFragments只是临时存储作用,后面glide会通过handler发送消息,将fragment从map中移除

    在这里插入图片描述

    3. ReqeustManager如何感知到Fragment生命周期?

    要回答这个问题,我们需要研究下SupportRequestManagerFragment构造器

    可以看到SupportRequestManagerFragment默认构造器中传入了一个ActivityFragmentLifecycle对象,这个对象的作用其实就是将fragment的生命周期事件传递给自己的订阅者,实现其生命周期的转发

    image

    想想看如果RequestManger实现了LifecycleListener接口,并注册到了ActivityFragmentLifecycle对象中会发生什么?
    没错,结果就是RequestManager能够感知到fragment的生命周期了,
    我们来看下代码发现RequestManger确实实现了LifeCycleListener,同时在构造器方法中实现了对lifecycle的注册

    至此 glide通过一个无UI的fragment实现了让RequestManager感知生命周期能力,以一张流程图总结生命周期事件传递分发

    SupportRequestManagerFragment ActivityFragmentLifecycle RequestManger onStart onStart onStart SupportRequestManagerFragment ActivityFragmentLifecycle RequestManger

    下图中就是RequestManager的部分实现

    在这里插入图片描述

    可以看到RequestManager里面实现了onStart、onStop、onDestroy方法

    • onStart:
      • 开启那些还没完成或请失败的resource加载请求(交给requestTracker)
      • targetTracker对其生命周期的转发
    • onStop:
      • 中止进行中的请求(交给requestTracker)
      • targetTracker对其生命周期的转发
    • onDestory:做一些资源的清理工作

    这些请求从哪来的呢?谁创建的?

    带着这个疑问我们继续来看load方法

    五、RequestManager.load(string)

    因为glide支持加载远程图片,本地资源文件,所以load这里是个重载方法,这个比较好理解

    在这里插入图片描述

    这里我们从常用的load(String)分析

      /**
       * Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(String)}.
       *
       * @return A new request builder for loading a {@link Drawable} using the given model.
       */
      @NonNull
      @CheckResult
      @Override
      public RequestBuilder<Drawable> load(@Nullable String string) {
        return asDrawable().load(string);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    可以load方法内部是创建了一个RequestBuilder并链式调用其load方法,RequestBuilder它可以通过给定的model(图片url)来加载成一个resouces(Drawable)

    RequestManager RequestBuilder load(String) RequestManager RequestBuilder
      @NonNull
      @CheckResult
      public RequestBuilder<Drawable> asDrawable() {
        return as(Drawable.class);
      }
      /**
       * Attempts to load the resource using any registered {@link
       * com.bumptech.glide.load.ResourceDecoder}s that can decode the given resource class or any
       * subclass of the given resource class.
       *
       * @param resourceClass The resource to decode.
       * @return A new request builder for loading the given resource class.
       */
      @NonNull
      @CheckResult
      public <ResourceType> RequestBuilder<ResourceType> as(
          @NonNull Class<ResourceType> resourceClass) {
        return new RequestBuilder<>(glide, this, resourceClass, context);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    as使用来创建一个加载指定资源类型的RequestBuilder方法,接下来看下其load方法

     public RequestBuilder<TranscodeType> load(@Nullable String string) {
        return loadGeneric(string);
      }
    
      private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
        this.model = model;
        isModelSet = true;
        return this;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    内部实现非常简单,就是把我们需要请求图片的url(在glide中可以理解为model)保存到RequestBuilder,顺便提下RequestBuilder继承了BaseRequestOptions,里面有我们所熟悉的centerCrop图片裁剪,占位图,内存缓存,磁盘缓存策略,优先级定义等方法

    在这里插入图片描述
    这些方法都可以理解为相关的配置信息,这些配置的信息将在后续流程使用到,可以看到我们在load中并没有找到我们的资源请求的创建?答案是在into方法中,在篇2给讲解到

  • 相关阅读:
    QT--线程
    【随手记】python语言的else语句在for、while等循环语句中的运用
    熵、信息增益----决策树原理分析、代码实现与绘图
    Python教程:迭代器的正确使用方法
    (附源码)spring boot校园管理系统 毕业设计 021104
    理解ELMo 模型
    【项目实战】自主实现 HTTP 项目(一)——tcp、http的创建与实现较兼容的行读取
    prize_p1
    27 行为型模式-解释器模式
    管理团队按这个模板做,让你成为优秀管理者
  • 原文地址:https://blog.csdn.net/dbs1215/article/details/126278449