Android 进阶学习(十二) Glide源码学习(一) 图片加载过程

Glide 作为Google 出品的图片加载库,在开发的过程中对我们的帮助是非常大的,网上也有很多关于他的文章,说他怎么怎么好,但是他就是再好我们如果不知道他的原理也肯定是记不住的,而且关于图片的操作在面试过程中是必然要问到的,如果你只是知道怎么用的话肯定是不能打动面试官的,如果你能从源码方面说一下,肯定会让对方眼前一亮的,废话不多说,我们由简入繁的开始分析一下一张图片在Glide都经历了什么,

想要弄清楚整个图片的加载过程,如果上来就看源码的话大家肯定会非常懵,还是需要先弄清楚每个类在Glide中扮演的角色,这样便于大家的理解,即使部分代码不懂,但是知道了他是干什么也能猜测一个大概,同时也方便我们在分析过程中查看

Glide 中重要的角色

1.Glide

Glide作为图片加载的入口, 当中保存着非常重要的数据,在整个请求中非常重要,创建方式: DCL 单例

2.RequestManagerRetriever

RequestManagerRetriever 作为RequestManager 管理者,调度着当前请求应该分配给哪个RequestManager,创建方式:new 伴随着Glide同时创建

3.RequestManager

RequestManager 作为请求的承载者,中控器, 在当中扮演着非常重要的角色, 创建方式: new 不同的是并不是每次请求都创建,而是在同一个activity中只创建一个,部分情况可能将这个请求分配给ApplicationContext,

4.Request

这个一看就知道是请求, 重要的请求类 SingleRequest ThumbnailRequestCoordinator (包含2个请求,判断也非常简单,后面我们会单独做分析)
创建方式 : 缓存池 ,防止大量创建对象浪费时间,频繁销毁对象导致内存抖动,同样的方式 Handler.obtainMessage 也是如此

5.RequestBuilder

用来构建请求时的参数,通常会继承开发者在全局的配置,如果有改动会替换响应的改动.创建方式:new 无特殊方式,但是需要注意的是RequestBuilder的创建开始的方法是 as(classType.class) ,即使是Glide.with(context).load(resId),看似我们是调用的load 的方法创建了这个RequestBuilder,实际操作还是调用的as 方法

 @NonNull
 @CheckResult
 @Override
 public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
   return asDrawable().load(resourceId);
 }
 @NonNull
 @CheckResult
 public RequestBuilder<Drawable> asDrawable() {
   return as(Drawable.class);
 }

6.Target

Target 是作为回调参与进来的,他不仅仅参与下载后作为最后资源出口,还会参与下载过程中获取图片的载体的宽高等等,

7.Engine

Engine 的做用是发起请求,实际的请求过程就是在他的内部实现的,创建方式:new 伴随着Glide 创建的

至此整个加载过程中涉及到的角色我们就分析完了,下面我们进入正题,开始分析一下最简单的请求

Glide.with(context).load(resId).into(imageView);

Glide.with(context)

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

先是getRetriever ,通过getRetriever 来获取RequestManager

Glide.getRetriever(@Nullable Context context)

 @NonNull
 private static RequestManagerRetriever getRetriever(@Nullable Context context) {
   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();
 }

显示check一下context ,然后通过Glide 获取RequestManagerRetriever

Glide.get(@NonNull Context context)

private static volatile Glide glide;
 @NonNull
 public static Glide get(@NonNull Context context) {
   if (glide == null) {
     synchronized (Glide.class) {
       if (glide == null) {
         checkAndInitializeGlide(context);///初始化配置信息
       }
     }
   }

   return glide;
 }

 private static void checkAndInitializeGlide(@ NonNull Context context) {
   // In the thread running initGlide(), one or more classes may call Glide.get(context).
   // Without this check, those calls could trigger infinite recursion.
   if (isInitializing) {
     throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
         + " use the provided Glide instance instead");
   }
   isInitializing = true;
   initializeGlide(context);
   isInitializing = false;
 }
 private static void initializeGlide(@NonNull Context context) {
   initializeGlide(context, new GlideBuilder());
 }  

GlideBuilder.build(Context context)

   if (engine == null) {
     engine =
         new Engine(
             memoryCache,
             diskCacheFactory,
             diskCacheExecutor,
             sourceExecutor,
             GlideExecutor.newUnlimitedSourceExecutor(),
             GlideExecutor.newAnimationExecutor(),
             isActiveResourceRetentionAllowed);
   }

   if (defaultRequestListeners == null) {
     defaultRequestListeners = Collections.emptyList();
   } else {
     defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
   }

   RequestManagerRetriever requestManagerRetriever =
       new RequestManagerRetriever(requestManagerFactory);

这里的GlideBuilder 初始化了非常多的配置信息,这里我贴了两个比较重要的Engine 和RequestManagerRetriever ,可以看到这些都是伴随着Glide 同时初始化的,也就是整个工程就只有一个,

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

现在再看上面的方法大家应该已经知道了getRetriever()方法的大概,如果是第一次调用的话会使用DCL单利模式创建 Glide ,伴随着Glide 的创建同时会初始化一些配置信息比如 : RequestManagerRetriever Engine 等

RequestManagerRetriever.get(context)

 @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) {
       return get(((ContextWrapper) context).getBaseContext());
     }
   }
   return getApplicationManager(context);
 }

可以看到如果不是在主线程就使用ApplicationManage,这里我看一下FragmentActivity的分支,他的处理方法比较特殊,具体怎么特殊我们进去看一下,

RequestManagerRetriever.get(@NonNull FragmentActivity activity)

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

这里没啥东西,继续往里面走supportFragmentGet

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

在这里看到了创建RequestManager 的方法,同时把自己创建的Fragemnt的 Lifecycle传递给了 RequestManager , 供RequestManager 来监听宿主Activity的状态,来停止请求,这里我们粘贴一些方法

 RequestManager(
     Glide glide,
     Lifecycle lifecycle,
     RequestManagerTreeNode treeNode,
     RequestTracker requestTracker,
     ConnectivityMonitorFactory factory,
     Context context) {
   this.glide = glide;
   this.lifecycle = lifecycle;
   this.treeNode = treeNode;
   this.requestTracker = requestTracker;
   this.context = context;

   connectivityMonitor =
       factory.build(
           context.getApplicationContext(),
           new RequestManagerConnectivityListener(requestTracker));

   // If we're the application level request manager, we may be created on a background thread.
   // In that case we cannot risk synchronously pausing or resuming requests, so we hack around the
   // issue by delaying adding ourselves as a lifecycle listener by posting to the main thread.
   // This should be entirely safe.
   if (Util.isOnBackgroundThread()) {
     mainHandler.post(addSelfToLifecycle);
   } else {
     lifecycle.addListener(this);
   }
   lifecycle.addListener(connectivityMonitor);
 .....
}

lifecycle.addListener(this); 方法将自身作为参数,就可以监听到状态了,
我们看看RequestManager在生命周期方法中他都干了什么

 @Override
 public synchronized void onStart() {
   resumeRequests();
   targetTracker.onStart();
 }

 /**
  * Lifecycle callback that unregisters for connectivity events (if the
  * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
  */
 @Override
 public synchronized void onStop() {
   pauseRequests();
   targetTracker.onStop();
 }

 /**
  * Lifecycle callback that cancels all in progress requests and clears and recycles resources for
  * all completed requests.
  */
 @Override
 public synchronized void onDestroy() {
   targetTracker.onDestroy();
   for (Target<?> target : targetTracker.getAll()) {
     clear(target);
   }
   targetTracker.clear();
   requestTracker.clearRequests();
   lifecycle.removeListener(this);
   lifecycle.removeListener(connectivityMonitor);
   mainHandler.removeCallbacks(addSelfToLifecycle);
   glide.unregisterRequestManager(this);
 }

在onDestroy 中回收信息,onStart 开始请求,onStop 暂停请求,看到这里我就知道了Glide 是如何与生命周期作为绑定的,

看到这里我们发现他将RequestManager 放到了SupportRequestManagerFragment 里面,过去看了一下SupportRequestManagerFragment ,他就是一个普通的Fragment,没什么特别的,我们继续看看他是如何得到这个Fragment的,继续看getSupportRequestManagerFragment

 @NonNull
 private SupportRequestManagerFragment getSupportRequestManagerFragment(
     @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
   SupportRequestManagerFragment current =
       (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
   if (current == null) {
     current = pendingSupportRequestManagerFragments.get(fm);
     if (current == null) {
       current = new SupportRequestManagerFragment();
       current.setParentFragmentHint(parentHint);
       if (isParentVisible) {
         current.getGlideLifecycle().onStart();
       }
       pendingSupportRequestManagerFragments.put(fm, current);
       fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
       handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
     }
   }
   return current;
 }

看到这里我们恍然大悟,他在FragmentActivity中绑定了一个Fragment,通过这个Fragment来共享改Activity 的RequestManager ,同时可以感知这个Activity 的 声明周期,

看到了这里已经将Glide.with(context) 看完了,继续看load(String url)

RequestManager.load(@Nullable String string)

 @NonNull
 @CheckResult
 @Override
 public RequestBuilder<Drawable> load(@Nullable String string) {
   return asDrawable().load(string);
 }

 @NonNull
 @CheckResult
 public RequestBuilder<Drawable> asDrawable() {
   return as(Drawable.class);
 }
 @NonNull
 @CheckResult
 public <ResourceType> RequestBuilder<ResourceType> as(
     @NonNull Class<ResourceType> resourceClass) {
   return new RequestBuilder<>(glide, this, resourceClass, context);
 }

可以看到即使我们调用RequestManager.load()方法,他最终还是调用了as 方法来new RequestBuilder,设置其他参数这里就不分析了,继续看RequestBuilder.into(@NonNull ImageView view)

RequestBuilder.into(@NonNull ImageView view)

 @NonNull
 public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
   Util.assertMainThread();
   Preconditions.checkNotNull(view);

   BaseRequestOptions<?> requestOptions = this;
   if (!requestOptions.isTransformationSet()
       && requestOptions.isTransformationAllowed()
       && view.getScaleType() != null) {
     // Clone in this method so that if we use this RequestBuilder to load into a View and then
     // into a different target, we don't retain the transformation applied based on the previous
     // View's scale type.
     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:
         // Do nothing.
     }
   }

   return into(
       glideContext.buildImageViewTarget(view, transcodeClass),
       /*targetListener=*/ null,
       requestOptions,
       Executors.mainThreadExecutor());
 }

这里针对ScanType 做了一些配置参数,但是我们使用的是最简单的方法,所以这些参数都没有,直接看下面的into 方法,
可以看到into方法的第一个参数是通过glideContext ,view ,transcodeClass就是我们使用 load 的时候所调用的as 方法中Drawable,

 @NonNull
 public <X> ViewTarget<ImageView, X> buildImageViewTarget(
     @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
   return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
 }

这里调用了ImageViewTargetFactory 的 buildTarget方法,没有什么特别的,

ImageViewTargetFactory.buildTarget(@NonNull ImageView view,@NonNull Class<Z> clazz)

public class ImageViewTargetFactory {
 @NonNull
 @SuppressWarnings("unchecked")
 public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
     @NonNull Class<Z> clazz) {
   if (Bitmap.class.equals(clazz)) {
     return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
   } else if (Drawable.class.isAssignableFrom(clazz)) {
     return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
   } else {
     throw new IllegalArgumentException(
         "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
   }
 }
}

可以看到如果是Drawable的话返回的就是DrawableImageViewTarget ,回去继续看into 方法

RequestBuilder <Y extends Target<TranscodeType>> Y into( @NonNull Y target,@Nullable RequestListener<TranscodeType> targetListener,BaseRequestOptions<?> options, Executor callbackExecutor)

 private <Y extends Target<TranscodeType>> Y into(
     @NonNull Y target,
     @Nullable RequestListener<TranscodeType> targetListener,
     BaseRequestOptions<?> options,
     Executor callbackExecutor) {
   Preconditions.checkNotNull(target);
   if (!isModelSet) {
     throw new IllegalArgumentException("You must call #load() before calling #into()");
   }

   Request request = buildRequest(target, targetListener, options, callbackExecutor);

   Request previous = target.getRequest();
   if (request.isEquivalentTo(previous)
       && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
     request.recycle();
     // If the request is completed, beginning again will ensure the result is re-delivered,
     // triggering RequestListeners and Targets. If the request is failed, beginning again will
     // restart the request, giving it another chance to complete. If the request is already
     // running, we can let it continue running without interruption.
     if (!Preconditions.checkNotNull(previous).isRunning()) {
       // Use the previous request rather than the new one to allow for optimizations like skipping
       // setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
       // that are done in the individual Request.
       previous.begin();
     }
     return target;
   }

   requestManager.clear(target);
   target.setRequest(request);
   requestManager.track(target, request);

   return target;
 }

看到这里我们终于将请求时候的参数都已经创建完毕了,已经开始创建Request 了,这里看到他首先判断了 isModelSet 这个变量,isModelSet这个变量就是在调用load 方法的时候设置true 的,所以看他抛出异常的文言,在into 方法之前必须先调用load 方法,接下来构建了一个Request

RequestBuilder buildRequest

 private Request buildRequest(
     Target<TranscodeType> target,
     @Nullable RequestListener<TranscodeType> targetListener,
     BaseRequestOptions<?> requestOptions,
     Executor callbackExecutor) {
   return buildRequestRecursive(
       target,
       targetListener,
       /*parentCoordinator=*/ null,
       transitionOptions,
       requestOptions.getPriority(),
       requestOptions.getOverrideWidth(),
       requestOptions.getOverrideHeight(),
       requestOptions,
       callbackExecutor);
 }

这里获取了RequestBuilder 的OverrideWidth和OverrideHeight,但是我们没有设置,这里应该是默认值,''

RequestBuilder buildRequestRecursive

private Request buildRequestRecursive(
     Target<TranscodeType> target,
     @Nullable RequestListener<TranscodeType> targetListener,
     @Nullable RequestCoordinator parentCoordinator,
     TransitionOptions<?, ? super TranscodeType> transitionOptions,
     Priority priority,
     int overrideWidth,
     int overrideHeight,
     BaseRequestOptions<?> requestOptions,
     Executor callbackExecutor) {

   // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
   ErrorRequestCoordinator errorRequestCoordinator = null;
   if (errorBuilder != null) {
     errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
     parentCoordinator = errorRequestCoordinator;
   }

   Request mainRequest =
       buildThumbnailRequestRecursive(
           target,
           targetListener,
           parentCoordinator,
           transitionOptions,
           priority,
           overrideWidth,
           overrideHeight,
           requestOptions,
           callbackExecutor);

   if (errorRequestCoordinator == null) {
     return mainRequest;
   }

   int errorOverrideWidth = errorBuilder.getOverrideWidth();
   int errorOverrideHeight = errorBuilder.getOverrideHeight();
   if (Util.isValidDimensions(overrideWidth, overrideHeight)
       && !errorBuilder.isValidOverride()) {
     errorOverrideWidth = requestOptions.getOverrideWidth();
     errorOverrideHeight = requestOptions.getOverrideHeight();
   }

   Request errorRequest =
       errorBuilder.buildRequestRecursive(
           target,
           targetListener,
           errorRequestCoordinator,
           errorBuilder.transitionOptions,
           errorBuilder.getPriority(),
           errorOverrideWidth,
           errorOverrideHeight,
           errorBuilder,
           callbackExecutor);
   errorRequestCoordinator.setRequests(mainRequest, errorRequest);
   return errorRequestCoordinator;
 }

这里我们没有设置erroe的信息, 所以返回的是buildThumbnailRequestRecursive

RequestBuilder buildThumbnailRequestRecursive


 private Request buildThumbnailRequestRecursive(
     Target<TranscodeType> target,
     RequestListener<TranscodeType> targetListener,
     @Nullable RequestCoordinator parentCoordinator,
     TransitionOptions<?, ? super TranscodeType> transitionOptions,
     Priority priority,
     int overrideWidth,
     int overrideHeight,
     BaseRequestOptions<?> requestOptions,
     Executor callbackExecutor) {
   if (thumbnailBuilder != null) {
     // Recursive case: contains a potentially recursive thumbnail request builder.
     if (isThumbnailBuilt) {
       throw new IllegalStateException("You cannot use a request as both the main request and a "
           + "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
     }

     TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
         thumbnailBuilder.transitionOptions;

     // Apply our transition by default to thumbnail requests but avoid overriding custom options
     // that may have been applied on the thumbnail request explicitly.
     if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
       thumbTransitionOptions = transitionOptions;
     }

     Priority thumbPriority = thumbnailBuilder.isPrioritySet()
         ? thumbnailBuilder.getPriority() : getThumbnailPriority(priority);

     int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
     int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
     if (Util.isValidDimensions(overrideWidth, overrideHeight)
         && !thumbnailBuilder.isValidOverride()) {
       thumbOverrideWidth = requestOptions.getOverrideWidth();
       thumbOverrideHeight = requestOptions.getOverrideHeight();
     }

     ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
     Request fullRequest =
         obtainRequest(
             target,
             targetListener,
             requestOptions,
             coordinator,
             transitionOptions,
             priority,
             overrideWidth,
             overrideHeight,
             callbackExecutor);
     isThumbnailBuilt = true;
     // Recursively generate thumbnail requests.
     Request thumbRequest =
         thumbnailBuilder.buildRequestRecursive(
             target,
             targetListener,
             coordinator,
             thumbTransitionOptions,
             thumbPriority,
             thumbOverrideWidth,
             thumbOverrideHeight,
             thumbnailBuilder,
             callbackExecutor);
     isThumbnailBuilt = false;
     coordinator.setRequests(fullRequest, thumbRequest);
     return coordinator;
   } else if (thumbSizeMultiplier != null) {
     // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
     ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
     Request fullRequest =
         obtainRequest(
             target,
             targetListener,
             requestOptions,
             coordinator,
             transitionOptions,
             priority,
             overrideWidth,
             overrideHeight,
             callbackExecutor);
     BaseRequestOptions<?> thumbnailOptions =
         requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);

     Request thumbnailRequest =
         obtainRequest(
             target,
             targetListener,
             thumbnailOptions,
             coordinator,
             transitionOptions,
             getThumbnailPriority(priority),
             overrideWidth,
             overrideHeight,
             callbackExecutor);

     coordinator.setRequests(fullRequest, thumbnailRequest);
     return coordinator;
   } else {
     // Base case: no thumbnail.
     return obtainRequest(
         target,
         targetListener,
         requestOptions,
         parentCoordinator,
         transitionOptions,
         priority,
         overrideWidth,
         overrideHeight,
         callbackExecutor);
   }
 }

这里没有设置缩略图信息,所以调用的是obtainRequest

RequestBuilder obtainRequest

 private Request obtainRequest(
     Target<TranscodeType> target,
     RequestListener<TranscodeType> targetListener,
     BaseRequestOptions<?> requestOptions,
     RequestCoordinator requestCoordinator,
     TransitionOptions<?, ? super TranscodeType> transitionOptions,
     Priority priority,
     int overrideWidth,
     int overrideHeight,
     Executor callbackExecutor) {
   return SingleRequest.obtain(
       context,
       glideContext,
       model,
       transcodeClass,
       requestOptions,
       overrideWidth,
       overrideHeight,
       priority,
       target,
       targetListener,
       requestListeners,
       requestCoordinator,
       glideContext.getEngine(),
       transitionOptions.getTransitionFactory(),
       callbackExecutor);
 }
}

没有逻辑,继续向下看

SingleRequest obtain

public static <R> SingleRequest<R> obtain(
     Context context,
     GlideContext glideContext,
     Object model,
     Class<R> transcodeClass,
     BaseRequestOptions<?> requestOptions,
     int overrideWidth,
     int overrideHeight,
     Priority priority,
     Target<R> target,
     RequestListener<R> targetListener,
     @Nullable List<RequestListener<R>> requestListeners,
     RequestCoordinator requestCoordinator,
     Engine engine,
     TransitionFactory<? super R> animationFactory,
     Executor callbackExecutor) {
   @SuppressWarnings("unchecked") SingleRequest<R> request =
       (SingleRequest<R>) POOL.acquire();
   if (request == null) {
     request = new SingleRequest<>();
   }
   request.init(
       context,
       glideContext,
       model,
       transcodeClass,
       requestOptions,
       overrideWidth,
       overrideHeight,
       priority,
       target,
       targetListener,
       requestListeners,
       requestCoordinator,
       engine,
       animationFactory,
       callbackExecutor);
   return request;
 }

看到了obtain 这个方法有没有想起来Handler.obtainMessage 的方法,没错,他们的逻辑都是一样的,使用了一个常量池来保存信息,这样可以节省创建对象的时间,和频繁销毁对象造成的内存抖动
这里我们看到如果没有设置缩略图信息和error 信息的时候都是创建SingleRequest 实例,我们回头继续看我们没看完的into方法,

private <Y extends Target<TranscodeType>> Y into(
    @NonNull Y target,
    @Nullable RequestListener<TranscodeType> targetListener,
    BaseRequestOptions<?> options,
    Executor callbackExecutor) {
  Preconditions.checkNotNull(target);
  if (!isModelSet) {
    throw new IllegalArgumentException("You must call #load() before calling #into()");
  }

  Request request = buildRequest(target, targetListener, options, callbackExecutor);

  Request previous = target.getRequest();
  if (request.isEquivalentTo(previous)
      && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
    request.recycle();
    // If the request is completed, beginning again will ensure the result is re-delivered,
    // triggering RequestListeners and Targets. If the request is failed, beginning again will
    // restart the request, giving it another chance to complete. If the request is already
    // running, we can let it continue running without interruption.
    if (!Preconditions.checkNotNull(previous).isRunning()) {
      // Use the previous request rather than the new one to allow for optimizations like skipping
      // setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
      // that are done in the individual Request.
      previous.begin();
    }
    return target;
  }

  requestManager.clear(target);
  target.setRequest(request);
  requestManager.track(target, request);

  return target;
}

这里他将target 和request 绑定了,所以才有target.getRequest(); 和 target.setRequest(request); 这两个方法,既然将他们绑定再来看 target.getRequest();,就知道他是什么意思,也就是获取之前绑定的请求,如果前后两个请求相同,则放弃新创建的请求,直接返回原来已有的请求,继续看看是如何将target 和 request 绑定的

ViewTarget.setRequest(@Nullable Request request)

 @Override
 public void setRequest(@Nullable Request request) {
   setTag(request);
 }
 private void setTag(@Nullable Object tag) {
   if (tagId == null) {
     isTagUsedAtLeastOnce = true;
     view.setTag(tag);
   } else {
     view.setTag(tagId, tag);
   }
 }

这个绑定就是将这个request 设置为view的tag,
接下来就应该是请求了requestManager.track(target, request); 就是将这个target 放入已请求的队列里面,同时开始请求

RequestManager track(@NonNull Target<?> target, @NonNull Request request)

 synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
   targetTracker.track(target);
   requestTracker.runRequest(request);
 }

RequestManager runRequest

 public void runRequest(@NonNull Request request) {
   requests.add(request);
   if (!isPaused) {
     request.begin();
   } else {
     request.clear();
     if (Log.isLoggable(TAG, Log.VERBOSE)) {
       Log.v(TAG, "Paused, delaying request");
     }
     pendingRequests.add(request);
   }
 }

看到了根据一个标识位来判断是否开启请求,这个请求就是根据生命周期判断的,上面我们已经分析过了,这里的调用了request.begin() 方法,我们在上面中创建Request是SingleRequest,去看他的begin方法

SingleRequest begin

   public synchronized void begin() {
       this.assertNotCallingCallbacks();
       this.stateVerifier.throwIfRecycled();
       this.startTime = LogTime.getLogTime();
       if (this.model == null) {
           if (Util.isValidDimensions(this.overrideWidth, this.overrideHeight)) {
               this.width = this.overrideWidth;
               this.height = this.overrideHeight;
           }

           int logLevel = this.getFallbackDrawable() == null ? 5 : 3;
           this.onLoadFailed(new GlideException("Received null model"), logLevel);
       } else if (this.status == SingleRequest.Status.RUNNING) {
           throw new IllegalArgumentException("Cannot restart a running request");
       } else if (this.status == SingleRequest.Status.COMPLETE) {
           this.onResourceReady(this.resource, DataSource.MEMORY_CACHE);
       } else {
           this.status = SingleRequest.Status.WAITING_FOR_SIZE;
           if (Util.isValidDimensions(this.overrideWidth, this.overrideHeight)) {
               this.onSizeReady(this.overrideWidth, this.overrideHeight);
           } else {
               this.target.getSize(this);
           }

           if ((this.status == SingleRequest.Status.RUNNING || this.status == SingleRequest.Status.WAITING_FOR_SIZE) && this.canNotifyStatusChanged()) {
               this.target.onLoadStarted(this.getPlaceholderDrawable());
           }

           if (IS_VERBOSE_LOGGABLE) {
               this.logV("finished run method in " + LogTime.getElapsedMillis(this.startTime));
           }

       }
   }

这里还是判断了一些状态,如果状态是正确的,就会根据我们是否设置了overrideWidth与overrideHeight 来判断走哪一个方法,如果我们设置了,那就是我们已经知道了需要加载的图片大小,如果不知道,就需要调用target 去计算宽高,

ViewTarget.getSize

void getSize(@NonNull SizeReadyCallback cb) {
     int currentWidth = getTargetWidth();
     int currentHeight = getTargetHeight();
     if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
       cb.onSizeReady(currentWidth, currentHeight);
       return;
     }

     // We want to notify callbacks in the order they were added and we only expect one or two
     // callbacks to be added a time, so a List is a reasonable choice.
     if (!cbs.contains(cb)) {
       cbs.add(cb);
     }
     if (layoutListener == null) {
       ViewTreeObserver observer = view.getViewTreeObserver();
       layoutListener = new SizeDeterminerLayoutListener(this);
       observer.addOnPreDrawListener(layoutListener);
     }
   }

这里需要等待ViewTree 的回调,在成功后会回调request 的onSizeReady 方法将计算后的宽高传入,

SingleRequest onSizeReady

   public synchronized void onSizeReady(int width, int height) {
       this.stateVerifier.throwIfRecycled();
       if (IS_VERBOSE_LOGGABLE) {
           this.logV("Got onSizeReady in " + LogTime.getElapsedMillis(this.startTime));
       }

       if (this.status == SingleRequest.Status.WAITING_FOR_SIZE) {
           this.status = SingleRequest.Status.RUNNING;
           float sizeMultiplier = this.requestOptions.getSizeMultiplier();
           this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
           this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
           if (IS_VERBOSE_LOGGABLE) {
               this.logV("finished setup for calling load in " + LogTime.getElapsedMillis(this.startTime));
           }

           this.loadStatus = this.engine.load(this.glideContext, this.model, this.requestOptions.getSignature(), this.width, this.height, this.requestOptions.getResourceClass(), this.transcodeClass, this.priority, this.requestOptions.getDiskCacheStrategy(), this.requestOptions.getTransformations(), this.requestOptions.isTransformationRequired(), this.requestOptions.isScaleOnlyOrNoTransform(), this.requestOptions.getOptions(), this.requestOptions.isMemoryCacheable(), this.requestOptions.getUseUnlimitedSourceGeneratorsPool(), this.requestOptions.getUseAnimationPool(), this.requestOptions.getOnlyRetrieveFromCache(), this, this.callbackExecutor);
           if (this.status != SingleRequest.Status.RUNNING) {
               this.loadStatus = null;
           }

           if (IS_VERBOSE_LOGGABLE) {
               this.logV("finished onSizeReady in " + LogTime.getElapsedMillis(this.startTime));
           }

       }
   }

看到这里整个加载的过程我们就已经分析完毕了,整个过程还是非常复杂的,但是只要足够耐心还是能看懂的,

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342