glide 源码分析笔记

glide 是目前android最广泛的图片加载框架之一,下面我们将分析其源码加载流程。

使用流程

glide 最基本的使用,如下,其他额外的功能,都是以建造者链式调用的基础上添加

Glide.with(context).load(url).into(targetView);

我们先通过艽野尘梦绘制的 glide 框架图来对 glide 总体有个初步了解

Glide框架图.jpg

glide.with

看下 with 代码:


  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }

  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }

  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

  public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getContext()).get(fragment);
  }

  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
     ....
    return Glide.get(context).getRequestManagerRetriever();
  }

可以看到 width的方法基本一致,都是通过 getRetriever 来获取到 RequestManagerRetriever 对象,然后再获取 RequestManager 对象并返回

Q: With() 的不同之处是什么呢,为什么要这样呢?

A:不同在于传入的参数不一致,可以是Context、Activity、Fragment等等。

因为 Glide 在加载图片的时候会绑定 with(context) 方法中传入的 context 的生命周期,如果传入的是 Activity ,那么在这个 Activity 销毁的时候 Glide 会停止图片的加载。这样避免了消耗多余的资源,也避免了在Activity销毁之后加载图片从而导致的空指针问题。

我们先 Glide.get(context):


  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      GeneratedAppGlideModule annotationGeneratedModule =
          getAnnotationGeneratedGlideModules(context.getApplicationContext());
      synchronized (Glide.class) {
        if (glide == null) { // 初始化
          checkAndInitializeGlide(context, annotationGeneratedModule);
        }
      }
    }
    return glide;
  }

 private static void initializeGlide( // 创建 GlideBuilder @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
    initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
  }

public final class GlideBuilder { // GlideBuilder 内容
  private final Map, TransitionOptions> defaultTransitionOptions = new ArrayMap<>();
  private Engine engine;
  private BitmapPool bitmapPool;
  private ArrayPool arrayPool;
  private MemoryCache memoryCache;
  private GlideExecutor sourceExecutor;
  private GlideExecutor diskCacheExecutor;
  private DiskCache.Factory diskCacheFactory;
  private MemorySizeCalculator memorySizeCalculator;
  private ConnectivityMonitorFactory connectivityMonitorFactory;
  private int logLevel = Log.INFO;
  private RequestOptionsFactory defaultRequestOptionsFactory =
      new RequestOptionsFactory() {
        @NonNull
        @Override
        public RequestOptions build() {
          return new RequestOptions();
        }
      };
  @Nullable private RequestManagerFactory requestManagerFactory;
  private GlideExecutor animationExecutor;
  private boolean isActiveResourceRetentionAllowed;
  @Nullable private List> defaultRequestListeners;
  private boolean isLoggingRequestOriginsEnabled;
  private boolean isImageDecoderEnabledForBitmaps;

........

}

看到 glide.get(context)内容也挺多的,但是最重要的是创建了 glideBuilder 来配置,如图片内存缓存、本地缓存等等。开发者可以传入自主定义的配置

接下来,我们看 RequestManagerRetriever 中 get(),同样该类 get() 也有几个:


// 根据传入不同的 Context ,获取不同的 RequestManager
  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 

          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
    return getApplicationManager(context);
  }

 public RequestManager get(@NonNull FragmentActivity activity) { .........}public RequestManager get(@NonNull Fragment fragment){.......}

  public RequestManager get(@NonNull Activity activity) {...........}

明显地看到,传入的 context 可以是 Application、FragmentActivity、Activity 或 ContextWrapper。

我们就拿其中一个来看,如传入 FragmentActivity ,代码如下所示:


public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) { // 不是主线程
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity); // 判断最低版本、activity 是否销毁
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

代码逻辑很简单,看注释即可知道,我们看其中关键方法 supportFragmentGet():


  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current = // 创建没有界面的 Fragment
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      Glide glide = Glide.get(context);
      requestManager = factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager); // Fragment 与 RequestManager 绑定,实现对 Activity 生命周期的监听
    }
    return requestManager;
  }

with() 就已经结束完了,总结一下:

1. 通过 RequestManagerRetriever 的 get() 获取 RequestManagerRetriever 对象,然后再通过该对象 get(context)获取 RequestManager 对象
2. 获取 RequestManager 对象时,get(context) 传参不同,有不同的处理:
a. context 是 Application,通过 getApplicationManager(Context context) 创建并返回一个 RequestManager 对象
b. context 是 FragmentActivity,通过 supportFragmentGet( ) 在当前 activity 创建并添加一个没有界面的 fragment,从而实现图片加载与 activity 的生命周期相绑定,之后创建并返回一个 RequestManager 对象

load(url)

上面说到 with()返回一个 RequestManager 对象,我们在该对象中,看 load(url):


  public RequestBuilder load(@Nullable String string) {
    return asDrawable().load(string);
  }

我们先看,asDrawable() :


  public RequestBuilder asDrawable() {
    return as(Drawable.class);
  }

// 创建 一个 RequestBuilder 并返回
  public  RequestBuilder as(
      @NonNull Class resourceClass) {
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }

明显地看到,asDrawable() 最终返回 RequestBuilder 对象,再结合 load(string):


 public RequestBuilder load(@Nullable String string) {
    return loadGeneric(string);
  }

.......

  private RequestBuilder loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }

load() 只是把数据传入 RequestBuilder 中,并将数据源是否已设置标志位 isModelSet = true。

最重要的是 asDrawable 构建 RequestBuilder 对象,明显地,RequestBuilder 就是一个 builder 模式,我们平时的一些额外配置

,就是通过 Builder 模式配置的,如


Glide.with(context)
    .load(url)
    .placeholder(R.drawable.place_image)
    .error(R.drawable.error_image)
    .into(imageView);

// 源码在 RequestBuilder 的父类 BaseRequestOptions 中

 public T error(@DrawableRes int resourceId) {
    if (isAutoCloneEnabled) {
      return clone().error(resourceId);
    }
    this.errorId = resourceId;
    fields |= ERROR_ID;
    this.errorPlaceholder = null;
    fields &= ~ERROR_PLACEHOLDER;
    return selfOrThrowIfLocked();
  }

好,load(url) 已经分析完了,主要是构建一个 RequestBuilder 对象,配置图片加载的请求。

into (imageView)

上面说到了 load(url) 创建了一个 RequestBuilder,配置图片加载的请求,但也仅仅是个请求,并没有执行。真正的执行请求是在 into() 中,我们看下这个方法:


public ViewTarget into(@NonNull ImageView view) {
    BaseRequestOptions requestOptions = this;
    if (!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed()   

       && view.getScaleType() != null) {
        switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions = requestOptions.clone().optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions = requestOptions.clone().optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions = requestOptions.clone().optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
      }
    }
   return into(
        // 根据 transcodeClass 类型不同 包装 view为 ViewTarget ,transcodeClass的值是 load(url)确定的
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null, // targetListener 监听图片加载是否成功
        requestOptions,
        Executors.mainThreadExecutor()); // 调用 execute 在主线程执行任务

  }

.....

 private > Y into(
      @NonNull Y target,
      @Nullable RequestListener targetListener,
      BaseRequestOptions options,
      Executor callbackExecutor) {
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    //创建当前 request,Request 是一个接口,我们获得的是 SingleRequest
    Request request = buildRequest(target, targetListener, options, callbackExecutor);
    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous) // 当前与上一个是否相同
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        previous.begin();
      }
      return target;
    }
    requestManager.clear(target);  // 清除 previous,防止重用,出现错位或闪烁
    target.setRequest(request);  // ViewTarget 与 请求绑定
    requestManager.track(target, request); // 执行 request
    return target;
  }

// 我们看 track()

 synchronized void track(@NonNull Target target, @NonNull Request request) {
    targetTracker.track(target); //监听 viewTarget 生命周期
    requestTracker.runRequest(request); // 执行请求
  }

// 再看 runRequest ()

  public void runRequest(@NonNull Request request) {
    requests.add(request);//加入请求列表中
    if (!isPaused) {
      request.begin(); // 非暂停状态,开始执行请求
    } else {
      request.clear();
      pendingRequests.add(request); // 暂停状态下,加入等待列表中
    }
  }

前面说了 request 是一个接口,我们获取到的是 SingleRequest,接着我们看该类里面的 begin()


 public void begin() {
    synchronized (requestLock) {
      assertNotCallingCallbacks();
      stateVerifier.throwIfRecycled();
      startTime = LogTime.getLogTime();
      if (model == null) {
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
          width = overrideWidth;
          height = overrideHeight;
        }
        int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
        onLoadFailed(new GlideException("Received null model"), logLevel);
        return;
      }
      if (status == Status.RUNNING) {
        throw new IllegalArgumentException("Cannot restart a running request");
      }
      // starting the new load.
      if (status == Status.COMPLETE) {
        onResourceReady(resource, DataSource.MEMORY_CACHE);
        return;
      }
      // Restarts for requests that are neither complete nor running can be treated as new requests
      // and can run again from the beginning.
      status = Status.WAITING_FOR_SIZE;
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        onSizeReady(overrideWidth, overrideHeight); // 尺寸已确定,准备执行请求
      } else {
        target.getSize(this); // 获取尺寸,然后再次调用 onSizeReady
      }
      if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
          && canNotifyStatusChanged()) {
        target.onLoadStarted(getPlaceholderDrawable()); // 开始加载,先显示占位图
      }
    }
  }

// 接下来,看 onSizeReady() 如何请求图片

 public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    synchronized (requestLock) {
      if (status != Status.WAITING_FOR_SIZE) {
        return;
      }
      status = Status.RUNNING;
      float sizeMultiplier = requestOptions.getSizeMultiplier();
      this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
      this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
      loadStatus =
          engine.load( // 核心代码,加载图片
              glideContext,
              model,
              requestOptions.getSignature(),
              this.width,
              this.height,
              requestOptions.getResourceClass(),
              transcodeClass,
              priority,
              requestOptions.getDiskCacheStrategy(),
              requestOptions.getTransformations(),
              requestOptions.isTransformationRequired(),
              requestOptions.isScaleOnlyOrNoTransform(),
              requestOptions.getOptions(),
              requestOptions.isMemoryCacheable(),
              requestOptions.getUseUnlimitedSourceGeneratorsPool(),
              requestOptions.getUseAnimationPool(),
              requestOptions.getOnlyRetrieveFromCache(),
              this,
              callbackExecutor);
      if (status != Status.RUNNING) {
        loadStatus = null;
      }
    }

我们来看下 load 内部的实现:


public  LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class resourceClass,
      Class transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map, Transformation> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb,
      Executor callbackExecutor) {
    EngineResource memoryResource;
    synchronized (this) {
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
      if (memoryResource == null) {// 缓存中没有存在,则从网络上拿
        return waitForExistingOrStartNewJob(
            glideContext,
            model,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            options,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache,
            cb,
            callbackExecutor,
            key,
            startTime);
      }
    }
    //拿到图片后的操作
    cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
    return null;
  }

看到,先从缓存中拉取,没有再去网络中请求,暂且不看网络是如何请求的,看下拿到图片后的操作 cb.onResourceReady()


public void onResourceReady(Resource resource, DataSource dataSource) {
    stateVerifier.throwIfRecycled();
    Resource toRelease = null;
    try {
      synchronized (requestLock) {

      if (resource == null) {
             GlideException exception =
                 new GlideException(
                     "Expected to receive a Resource with an "
                      + "object of "
                      + transcodeClass
                      + " inside, but instead got null.");
             onLoadFailed(exception); //回调失败
             return;
        }

        .....
        Object received = resource.get();
        ......
        onResourceReady((Resource) resource, (R) received, dataSource); // 成功后的处理
      }
    } finally {
      if (toRelease != null) {
        engine.release(toRelease);
      }
    }
  }

......

private void onResourceReady(Resource resource, R result, DataSource dataSource) {
    // We must call isFirstReadyResource before setting status.
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    isCallingCallbacks = true;
    try {
      boolean anyListenerHandledUpdatingTarget = false;
      if (requestListeners != null) {
        for (RequestListener listener : requestListeners) {
          anyListenerHandledUpdatingTarget |=
              listener.onResourceReady(result, model, target, dataSource, isFirstResource);
        }
      }
      ......
      if (!anyListenerHandledUpdatingTarget) {
        Transition animation = animationFactory.build(dataSource, isFirstResource);
        target.onResourceReady(result, animation); // 最终 view.setImageBitmap(resource);
      }
    } finally {
      isCallingCallbacks = false;
    }
    notifyLoadSuccess();
  }

获取图片后,还是一步一步到 setResource(),最后调用常用的图片加载方法

into() 基本分析完了,暂且忽略了网络请求图片部分(过于复杂,下次再分析),总结一下:

将 view 包装成 viewTarget

创建一个 SingleRequest ,包含了请求的信息
清除这个 viewTarget 之前绑定的请求,绑定新的请求
执行新的请求,先查缓存,没有再去网络请求
获取图片数据之后,成功则会调用notifyLoadSuccess()并设置 setImagexxx,失败则onLoadFailed()和显示获取失败占位图

参考

Glide源码分析

Android主流三方库源码分析(三、深入理解Glide源码)

你可能感兴趣的:(glide 源码分析笔记)