glide-源码解析-1

glide-源码解析-1

  • glide-源码解析-1
    • 一、前言
    • 二、使用
    • 三、主流程
    • 四、with
      • 1. Glide.with(Activity)
      • 2. glide为啥要创建fragment?
      • 3. ReqeustManager如何感知到Fragment生命周期?
    • 五、RequestManager.load(string)

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)

三、主流程

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)

glide-源码解析-1_第1张图片

可以看到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);
  }
  ...

看下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);
  }

最后一句进去看下

glide-源码解析-1_第2张图片

可以看到这里面其实返回的是一个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));
    }
}

可以看到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;
  }

可以看到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;
}

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

glide-源码解析-1_第3张图片

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

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

glide-源码解析-1_第4张图片

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

glide-源码解析-1_第5张图片

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

glide-源码解析-1_第6张图片

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

SupportRequestManagerFragment ActivityFragmentLifecycle RequestManger onStart onStart onStart SupportRequestManagerFragment ActivityFragmentLifecycle RequestManger

下图中就是RequestManager的部分实现

glide-源码解析-1_第7张图片

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

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

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

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

五、RequestManager.load(string)

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

glide-源码解析-1_第8张图片

这里我们从常用的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);
  }

可以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);
  }

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;
  }

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

glide-源码解析-1_第9张图片
这些方法都可以理解为相关的配置信息,这些配置的信息将在后续流程使用到,可以看到我们在load中并没有找到我们的资源请求的创建?答案是在into方法中,在篇2给讲解到

你可能感兴趣的:(glide,android,java)