[Glide系列第1篇]Glide源码分析之加载图片流程(1/2)

前言:开发的过程中一定少不了图片加载库,对于Android图片加载库,我们在最常听到的有老牌图片加载框架UniversalImageLoader,Glide和Picasso,还有Facebook的Fresco。关于老牌框架UIL在这里先不谈了,我们的目的也是选择一款适合自己的框架,关于Glide和Picasso,可以说这两个框架就像龙凤胎,有太多的相似点,它们的比较看这篇文章,里面详细的比较了这两款框架,关于Fresco,可以说是结合了许多图片库的优点,基本满足了所有的网络图片展示需求,拥有三级缓存,内存管理是它的特色,但是api没有其他的使用起来简便,也不能加载gif图,并且体积几乎有5M, 对比glide只有几百k,所以一般使用这个框架的都是对图片处理需求大要求高那种。所以根据自己的偏好选择一款就好了(没有最好的框架,只有最适合自己的框架)。本文是偏爱Glide,并对加载流程进行分析。

本文章是基于Glide V4版本, 和V3会有差异
关于V4和V3版本的差异,参考官网说明,当你读完源码,可能就更能理解所做的改变了。Glide从v3迁移到v4
全篇篇幅较长 编辑的时候出现了好多次如下图片,所以分了两篇写加载的过程。感觉能把代码撸到最后的都是战士。。

关于Glide加载图片最常使用的一句,也是最简单的语句就是::

Glide.with(this).load(url).into(imageView);

三步走:先with(),再load(),最后into()

看似简单的一句话,却想不到在这句话下面做了多少的处理,看到最后,会惊异于Glide库的强大。
话不多少,我就是从头一点一点的过到最后,耗时也是蛮久,中间几度迷路在代码中,看到眼睛都要花了,😁😀


先放一张总结的思维脑图,帮助大家理清

1.Glide.with()

with()方法是Glide类中的一组静态方法,它有好几个方法重载,正是通过这几个重载,with()方法才可以接收Context、Activity或者Fragment类型的参数。也就是说我们选择的范围非常广,不管是在Activity还是Fragment中调用with()方法,都可以直接传this。那如果调用的地方既不在Activity中也不在Fragment中呢?也没关系,我们可以获取当前应用程序的ApplicationContext,传入到with()方法当中。
public class Glide {
         ...省略
 /*
 *  Begin a load with Glide by passing in a context.
  * @param context Any context, will not be retained.
  * @return A RequestManager for the top level application that can be used to start a load.
  * @see #with(android.app.Activity)
  * @see #with(android.app.Fragment)
  * @see #with(android.support.v4.app.Fragment)
  * @see #with(android.support.v4.app.FragmentActivity)
  */
 public static RequestManager with(Context context) {
   return getRetriever(context).get(context);
 }
 public static RequestManager with(Activity activity) {
   return getRetriever(activity).get(activity);
 }
public static RequestManager with(FragmentActivity activity) {
   return getRetriever(activity).get(activity);
 }
 public static RequestManager with(android.app.Fragment fragment) {
   return getRetriever(fragment.getActivity()).get(fragment);
 }
public static RequestManager with(Fragment fragment) {
   return getRetriever(fragment.getActivity()).get(fragment);
 }
 public static RequestManager with(View view) {
   return getRetriever(view.getContext()).get(view);
 }
}

然后在重载的方法中通过getRetriever(传入context)
public class Glide {
  ...省略
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    // Context could be null for other reasons (ie the user passes in null), but in practice it will
    // only occur due to errors with the Fragment lifecycle.
    Preconditions.checkNotNull(
        context,
        "You cannot start a load on a not yet attached View or a  Fragment where getActivity() "
            + "returns null (which usually occurs when getActivity() is called before the Fragment "
            + "is attached or after the Fragment is destroyed).");
    return Glide.get(context).getRequestManagerRetriever();
  }
}
通过静态get()方法得到一个Glide对象,单例实现,保证一个应用程序只有一个实例。在 checkAndInitializeGlide(context);这个方法中做一些实例重要对象的操作。(自行查看。比如缓存对象、注解、管理请求的工厂等)然后通过getRequestManagerRetriever()返回一个RequestManagerRetriever对象
public class Glide {
        ...省略
  /**
   * Get the singleton.
   *
   * @return the singleton
   */
  public static Glide get(Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context);
        }
      }
    }

    return glide;
  }
  public RequestManagerRetriever getRequestManagerRetriever() {
    return requestManagerRetriever;
  }
}
最后调用RequestManagerRetriever的实例get()方法的一系列重载,去获取RequestManager对象。(Glide.with()的产物)
RequestManagerRetriever类
public class RequestManagerRetriever implements Handler.Callback {
...省略
 public RequestManager get(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) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
    return getApplicationManager(context);
  }

  public RequestManager get(FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, null /*parentHint*/);
    }
  }

  public RequestManager get(Fragment fragment) {
    Preconditions.checkNotNull(fragment.getActivity(),
          "You cannot start a load on a fragment before it is attached or after it is destroyed");
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getActivity().getApplicationContext());
    } else {
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getActivity(), fm, fragment);
    }
  }

  public RequestManager get(Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(activity, fm, null /*parentHint*/);
    }
  }

  public RequestManager get(View view) {
    if (Util.isOnBackgroundThread()) {
      return get(view.getContext().getApplicationContext());
    }

    Preconditions.checkNotNull(view);
    Preconditions.checkNotNull(view.getContext(),
        "Unable to obtain a request manager for a view without a Context");
    Activity activity = findActivity(view.getContext());
    // The view might be somewhere else, like a service.
    if (activity == null) {
      return get(view.getContext().getApplicationContext());
    }

    if (activity instanceof FragmentActivity) {
      Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
      return fragment != null ? get(fragment) : get(activity);
    }

    // Standard Fragments.
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
      return get(activity);
    }
    return get(fragment);
  }
}
从这些get重载方法里我们可以了解到:
  • 对于Application类型参数:

    • 在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理。
    • 如果传入的就是Application类型参数(Glide.with(getApplicationContext())),那么会通过getApplicationManager()方法返回RequestManager。Glide加载图片的生命周期是和with里的参数保持一致,而对于Application类型,只有当应用程序被杀掉的时候,图片加载才会停止。
RequestManagerRetriever类
...
private final RequestManagerFactory factory;
private volatile RequestManager applicationManager;
...
  private RequestManager getApplicationManager(Context context) {
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }

    return applicationManager;
  }
  /**
   * Used internally to create {@link RequestManager}s.
   */
  public interface RequestManagerFactory {
    RequestManager build(
        Glide glide,
        Lifecycle lifecycle,
        RequestManagerTreeNode requestManagerTreeNode,
        Context context);
  }
  • 对于非Application类型:

最终的流程是一样的:
首先是获取 自己的FragmentManager,然后
  • Fragment类型调用supportFragmentGet()方法,在这个方法里调用getSupportRequestManagerFragment()
  • Activity类型调用fragmentGet()方法,在这个方法里调用getRequestManagerFragment()
可以看到在这两个方法做了相同的事:添加一个新的Fragment---RequestManagerFragment到当前页面;而这个Fragment的作用就是为了方便Glide控制生命周期,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了。
RequestManagerRetriever类
  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.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
  private RequestManager fragmentGet(Context context, android.app.FragmentManager fm,
      android.app.Fragment parentHint) {
    RequestManagerFragment current = getRequestManagerFragment(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.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
  SupportRequestManagerFragment getSupportRequestManagerFragment(
      final FragmentManager fm, Fragment parentHint) {
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
  RequestManagerFragment getRequestManagerFragment(
      final android.app.FragmentManager fm, android.app.Fragment parentHint) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }
RequestManagerFragment类
  public RequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }

  // For testing only.
  @SuppressLint("ValidFragment")
  RequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
  }
至此 我们了解了Glide.with()方法背后的操作。一系列操作最终得到的是RequestManager

2.load()

load()方法明显就在RequestManager类,那我们接下来看一下这个load方法做了什么
public class RequestManager implements LifecycleListener {
...省略
  /**
   * A helper method equivalent to calling {@link #asDrawable()} and then {@link
   * RequestBuilder#load(Object)} with the given model.
   *
   * @return A new request builder for loading a {@link Drawable} using the given model.
   */
  @CheckResult
  public RequestBuilder<Drawable> load(@Nullable Object model) {
    return asDrawable().load(model);
  }
 @CheckResult
  public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }
  @CheckResult
  public <ResourceType> RequestBuilder<ResourceType> as(Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }
}
能调用RequestManager类的load方法,说明还没有指定类型,此时load方法默认置为asDrawable(),然后通过返回的RequestBuilder类中的load()加载图片,最终返回RequestBuilder<Drawable>。
而我们知道实际使用的时候会有加载为asBitmap、asFile()等操作,此时我们看这几个方法
RequestManager类
  private static final RequestOptions DECODE_TYPE_BITMAP = decodeTypeOf(Bitmap.class).lock();
  private static final RequestOptions DECODE_TYPE_GIF = decodeTypeOf(GifDrawable.class).lock();
  @CheckResult
  public RequestBuilder<Bitmap> asBitmap() {
    return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
  }
  @CheckResult
  public RequestBuilder<GifDrawable> asGif() {
    return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
  }
  @CheckResult
  public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }
  @CheckResult
  public RequestBuilder<File> asFile() {
    return as(File.class).apply(skipMemoryCacheOf(true));
  }
  @CheckResult
  public <ResourceType> RequestBuilder<ResourceType> as(Class<ResourceType> resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }
然后调用RequestManager类的apply方法返回RequestBuilder<TranscodeType>
RequestManager类
  @CheckResult
  public RequestBuilder<TranscodeType> apply(@NonNull RequestOptions requestOptions) {
    Preconditions.checkNotNull(requestOptions);
    this.requestOptions = getMutableOptions().apply(requestOptions);
    return this;
  }
此时load还是由RequestBuilder类调用,所以就是先确定类型,如果不指定 默认为asDrawable
而对于RequestBuilder类的load方法也有多个重载,这个方法用于指定待加载的图片资源,所以也就说明Glide支持加载各种各样的图片资源,包括网络图片、本地图片、应用资源、二进制流、Uri对象,Url对象,String字符串
 RequestBuilder类
public class RequestBuilder<TranscodeType> implements Cloneable {
  public RequestBuilder<TranscodeType> load(@Nullable Object model) {
    return loadGeneric(model);
  }
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
    return loadGeneric(bitmap)
        .apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
  }
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable Drawable drawable) {
    return loadGeneric(drawable)
        .apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
  }
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
  }
  public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
    return loadGeneric(uri);
  }
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable File file) {
    return loadGeneric(file);
  }
  @CheckResult
  public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
    return loadGeneric(resourceId).apply(signatureOf(ApplicationVersionSignature.obtain(context)));
  }
public RequestBuilder<TranscodeType> load(@Nullable URL url) {
    return loadGeneric(url);
  }
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable byte[] model) {
    return loadGeneric(model).apply(signatureOf(new ObjectKey(UUID.randomUUID().toString()))
        .diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true /*skipMemoryCache*/));
  }

  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }
}
所以实际使用时,我们还可以根据需要这样使用load()方法:
// 加载本地图片
File file = new File(getExternalCacheDir() + "/image.jpg");
Glide.with(this).load(file).into(imageView);

// 加载应用资源
int resource = R.drawable.image;
Glide.with(this).load(resource).into(imageView);

// 加载二进制流
byte[] image = getImageBytes();
Glide.with(this).load(image).into(imageView);

// 加载Uri对象
Uri imageUri = getImageUri();
Glide.with(this).load(imageUri).into(imageView);
现在我们肯定是继续看loadGeneric这个方法了,这个方法最终返回的也就是
RequestBuilder<TranscodeType> 这个类本身,也就是接下来into的操作也是在这个类中

关于into篇幅太长,所以单独放到一篇文章中

【两篇就懂系列】Glide源码分析之加载图片流程(2/2)

其他系列文章:

Glide源码分析流程思维导图

【一篇就懂系列】Glide源码分析之缓存处理

Glide图片加载库从v3迁移到v4的改变和使用

推荐阅读更多精彩内容