Glide源码流程分析


Glide.with(this).load("").into();

with()方法:包含Glide的初始化, 以及RequestManager的初始化

Glide内:RequestManager的初始化

@NonNull

public static RequestManager with(@NonNull FragmentActivity activity) {

   return getRetriever(activity).get(activity);

}

@NonNull

   public RequestManager get(@NonNull FragmentActivity activity) {

       if (Util.isOnBackgroundThread()) {

           return this.get(activity.getApplicationContext());

       } else {

           assertNotDestroyed(activity);

           androidx.fragment.app.FragmentManager fm = activity.getSupportFragmentManager();

           return this.supportFragmentGet(activity, fm, (Fragment)null, isActivityVisible(activity));

       }

   }


    @NonNull

   private RequestManager supportFragmentGet(@NonNull Context context, @NonNull androidx.fragment.app.FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {

       SupportRequestManagerFragment current = this.getSupportRequestManagerFragment(fm, parentHint, isParentVisible);//1.生成一个fragment

       RequestManager requestManager = current.getRequestManager();

       if (requestManager == null) {

           Glide glide = Glide.get(context);

           requestManager = this.factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);//2.使用工厂RequestManagerFactory生成一个RequestManager

           current.setRequestManager(requestManager);//3.将requestManager与生成的SupportRequestManagerFragment进行绑定

       }

       return requestManager;

   }

以Activity为例子:

1.首先会为当前activity生成绑定一个SupportRequestManagerFragment

2.使用工厂RequestManagerFactory生成一个RequestManager,参数分别是Gilde,LifeCycle, SupportFragmentRequestManagerTreeNode(),上下文本身(这里指的activity)

3.将requestManager与生成的SupportRequestManagerFragment进行绑定

laod()方法:-> 返回一个RequestBuilder<Drawable>

RequestManager内:

public RequestBuilder<Drawable> load(@Nullable String string) {

  return asDrawable().load(string);

}

public RequestBuilder<Drawable> asDrawable() {

  return as(Drawable.class);

}


public <ResourceType> RequestBuilder<ResourceType> as(

    @NonNull Class<ResourceType> resourceClass) { //

  return new RequestBuilder<>(glide, this, resourceClass, context);//1.生成一个RequestBilder 参数分别是gilde ResuestManager,Drawable.class,context上下文(activity)

}

RequestBuilder内:

@Override

  public RequestBuilder<TranscodeType> load(@Nullable Object model) {

   return loadGeneric(model);

  }

  @NonNull

  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {

   this.model = model;

   isModelSet = true;

   return this;

  }

这里以load(参数为string资源连接)为例:

1.生成一个RequestBilder 参数分别是gilde ResuestManager,Drawable.class,context上下文(activity)

2.将传入的资源链接(图片链接"xxx")赋值给内部私有变量private Object model 并返回RequestBilder

into()方法:

RequestBilder内:into参数以ImageView为例

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {

  Util.assertMainThread();//UI操作必须是在UI线程进行

  Preconditions.checkNotNull(view);

  RequestOptions requestOptions = this.requestOptions;

  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()) { //根据设置的scaleType初始化不同的Options

     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), //返回一个DrawableImageViewTarget

     /*targetListener=*/ null,

     requestOptions);

}

private <Y extends Target<TranscodeType>> Y into(

     @NonNull Y target, // 类型为DrawableImageViewTarget

     @Nullable RequestListener<TranscodeType> targetListener,

     @NonNull RequestOptions options) {

   Util.assertMainThread();

   Preconditions.checkNotNull(target);

   if (!isModelSet) {

     throw new IllegalArgumentException("You must call #load() before calling #into()");

   }

   options = options.autoClone();

   //参数 target==DrawableImageViewTarget, targetListener == null

   Request request = buildRequest(target, targetListener, options); //1.构建并返回一个SingleRequest

   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);//2.给目标imageView设置tag标记

   requestManager.track(target, request); //3.运行Request 开始从三级缓存以及网络中请求数据

   return target;

  }

into方法内部三步:

1.构建并返回一个SingleRequest

2.给目标imageView设置tag标记

3.运行Request 开始从三级缓存以及网络中请求数据

真正开始请求数据的地方:3. requestManager.track(target, request)  参数为返回一个DrawableImageViewTarget以及SingleRequest

RequestManager内部:

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

  targetTracker.track(target);

  requestTracker.runRequest(request); //执行request

}

RequestTracker内:

public void runRequest(@NonNull Request request) {

  requests.add(request);

  if (!isPaused) {

   request.begin(); //SingleRequest begin()

  } else {

   if (Log.isLoggable(TAG, Log.VERBOSE)) {

     Log.v(TAG, "Paused, delaying request");

   }

   pendingRequests.add(request);

  }

}

SingleRequest内:

@Override

public void begin() {

  assertNotCallingCallbacks();

  stateVerifier.throwIfRecycled();

  startTime = LogTime.getLogTime();

  if (model == null) {

   if (Util.isValidDimensions(overrideWidth, overrideHeight)) {

     width = overrideWidth;

     height = overrideHeight;

   }

   // Only log at more verbose log levels if the user has set a fallback drawable, because

   // fallback Drawables indicate the user expects null models occasionally.

   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");

  }

  // If we're restarted after we're complete (usually via something like a notifyDataSetChanged

  // that starts an identical request into the same Target or View), we can simply use the

  // resource and size we retrieved the last time around and skip obtaining a new size, starting a

  // new load etc. This does mean that users who want to restart a load because they expect that

  // the view size has changed will need to explicitly clear the View or Target before 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)) { //判断ImageView宽高是否正确

   onSizeReady(overrideWidth, overrideHeight); //开始加载

  } else {

   target.getSize(this);

  }

  if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)

     && canNotifyStatusChanged()) {

   target.onLoadStarted(getPlaceholderDrawable());

  }

  if (IS_VERBOSE_LOGGABLE) {

   logV("finished run method in " + LogTime.getElapsedMillis(startTime));

  }

}

@Override

  public void onSizeReady(int width, int height) {

   stateVerifier.throwIfRecycled();

   if (IS_VERBOSE_LOGGABLE) {

     logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));

   }

   if (status != Status.WAITING_FOR_SIZE) {

     return;

   }

   status = Status.RUNNING; //修改加载的状态为RUNNING

   float sizeMultiplier = requestOptions.getSizeMultiplier();

   this.width = maybeApplySizeMultiplier(width, sizeMultiplier);

   this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

   if (IS_VERBOSE_LOGGABLE) {

     logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));

   }

   //真正开始加载数据到来

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

   // This is a hack that's only useful for testing right now where loads complete synchronously

   // even though under any executor running on any thread but the main thread, the load would

   // have completed asynchronously.

   if (status != Status.RUNNING) {

     loadStatus = null;

   }

   if (IS_VERBOSE_LOGGABLE) {

     logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));

   }

  }

最后执行的方法来到Engine.load();

public <R> LoadStatus load(

   GlideContext glideContext,

   Object model,

   Key signature,

   int width,

   int height,

   Class<?> resourceClass,

   Class<R> transcodeClass,

   Priority priority,

   DiskCacheStrategy diskCacheStrategy,

   Map<Class<?>, Transformation<?>> transformations,

   boolean isTransformationRequired,

   boolean isScaleOnlyOrNoTransform,

   Options options,

   boolean isMemoryCacheable,

   boolean useUnlimitedSourceExecutorPool,

   boolean useAnimationPool,

   boolean onlyRetrieveFromCache,

   ResourceCallback cb) {

  Util.assertMainThread();

  long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

  EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,

     resourceClass, transcodeClass, options);

    //1.首先从正在活动的视图资源ActiveResources中开始取

  EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);

  if (active != null) {

   cb.onResourceReady(active, DataSource.MEMORY_CACHE);

   if (VERBOSE_IS_LOGGABLE) {

     logWithTimeAndKey("Loaded resource from active resources", startTime, key);

   }

   return null;

  }

    //2.从LruCache内存缓存中取

  EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); //

  if (cached != null) {

   cb.onResourceReady(cached, DataSource.MEMORY_CACHE);

   if (VERBOSE_IS_LOGGABLE) {

     logWithTimeAndKey("Loaded resource from cache", startTime, key);

   }

   return null;

  }

  EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);

  if (current != null) {

   current.addCallback(cb);

   if (VERBOSE_IS_LOGGABLE) {

     logWithTimeAndKey("Added to existing load", startTime, key);

   }

   return new LoadStatus(cb, current);

  }

  EngineJob<R> engineJob =

     engineJobFactory.build(

         key,

         isMemoryCacheable,

         useUnlimitedSourceExecutorPool,

         useAnimationPool,

         onlyRetrieveFromCache);

  DecodeJob<R> decodeJob =

     decodeJobFactory.build(

         glideContext,

         model,

         key,

         signature,

         width,

         height,

         resourceClass,

         transcodeClass,

         priority,

         diskCacheStrategy,

         transformations,

         isTransformationRequired,

         isScaleOnlyOrNoTransform,

         onlyRetrieveFromCache,

         options,

         engineJob);

  jobs.put(key, engineJob);

  engineJob.addCallback(cb);

  engineJob.start(decodeJob); //3.从硬盘缓存中取

  if (VERBOSE_IS_LOGGABLE) {

   logWithTimeAndKey("Started new load", startTime, key);

  }

  return new LoadStatus(cb, engineJob);

}

1.首先从正在活动的视图资源ActiveResources中开始取

2.从LruCache内存缓存中取

3.从硬盘缓存中取

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

推荐阅读更多精彩内容