Glide 源碼解析 ----- android source code for Glide 4.x

作為google主推的一款圖片加載框架,從glide3.x 到glide4.x加入apt的注解編譯;詳細(xì)的使用可以詳見官方文檔
[Glide v4] https://muyangmin.github.io/glide-docs-cn/
ps:之前在csdn 簡書第一篇 歡迎大家瀏覽

  • 首先來看Glide的基本使用:

(1)支持Memory和Disk圖片緩存兴枯。
(2)支持gif和webp格式圖片。
(3)根據(jù)Activity/Fragment生命周期自動(dòng)管理請求。
(4)使用Bitmap Pool可以使Bitmap復(fù)用。*
(5)對(duì)于回收的Bitmap會(huì)主動(dòng)調(diào)用recycle会喝,減小系統(tǒng)回收壓力肌索。

       GlideApp.with(this)
            //.asBitmap()   --- 轉(zhuǎn)換為bitmap
            //.asDrawable() ---- 轉(zhuǎn)換為drawable
            .asGif() --- 轉(zhuǎn)換為gif
            .load(url)
            .placeholder(R.mipmap.ic_launcher_round)
            .error(R.mipmap.ele)
            .fitCenter()
            //.fallback()當(dāng)請求圖片為null的時(shí)候
            .into(mIv);

在Glide v4中通過注解會(huì)在build 下apt生成部分外部文件 來操作glide,大大提高glide的可定制性,可以去看文章開頭的官網(wǎng)地址來看使用方式;下面的解析以v4為準(zhǔn)

  1. 首先來看glide的初始化:

GlideApp.with(this)


GlideApp:
  @NonNull
  public static GlideRequests with(@NonNull FragmentActivity arg0) {
    return (GlideRequests) Glide.with(arg0);
  }

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

這里是對(duì)Glide的初始化,以及對(duì)生命周期的管理:
核心代碼:

    getRetriever(activity).get(activity);

其中 getRetriever(activity)是glide的初始化

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

這里主要來看Glide.get(context):

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

  @SuppressWarnings("deprecation")
  private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
    ......省略部分代碼

    Glide glide = builder.build(applicationContext);


    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      module.registerComponents(applicationContext, glide, glide.registry);
    }
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }
    applicationContext.registerComponentCallbacks(glide);
    Glide.glide = glide;
  }

在initializeGlide中有一個(gè)構(gòu)建中模式的glide初始化,見怪不怪這是glide的真正初始化: Glide glide = builder.build(applicationContext);
繼續(xù)深入:

@NonNull
  public Glide build(@NonNull Context context) {
    if (sourceExecutor == null) {
      sourceExecutor = GlideExecutor.newSourceExecutor();
    }

    if (diskCacheExecutor == null) {
      diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
    }

    if (animationExecutor == null) {
      animationExecutor = GlideExecutor.newAnimationExecutor();
    }

    if (memorySizeCalculator == null) {
      memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
    }

    if (connectivityMonitorFactory == null) {
      connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
    }

    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
        bitmapPool = new LruBitmapPool(size);
      } else {
        bitmapPool = new BitmapPoolAdapter();
      }
    }

    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }

    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }

    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }

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

    RequestManagerRetriever requestManagerRetriever =
        new 
(requestManagerFactory);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);
  }

在這里glide初始化就完全初始化完畢:
相關(guān)圖片線程池---bitmapPool
圖片加載器engin等的初始化 等就基本完成了
當(dāng)然沒有必要去細(xì)究其具體的參數(shù),主要是理解其思想;

ok~到這里 glide的初始化完畢,下面通過glide的api

    getRetriever(activity).get(activity);

看到其中的get方法沒有,這里是glide的一個(gè)亮點(diǎn);通過傳入activity/fragment/或者view等來控制圖片加載的周期來提高其性能:
下面看具體的代碼:


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

  @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, null /*parentHint*/);
    }
  }

  @NonNull
  public RequestManager get(@NonNull 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);
    }
  }

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

  @NonNull
  public RequestManager get(@NonNull 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());
    }

    // Support Fragments.
    // Although the user might have non-support Fragments attached to FragmentActivity, searching
    // for non-support Fragments is so expensive pre O and that should be rare enough that we
    // prefer to just fall back to the Activity directly.
    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);
  }

可以看到glide 支持的是fragmentActivity/activity/fragment/view/context;其中view是通過判斷其所依托的碎片來進(jìn)行周期管理;
殊途同歸,下面以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, null /*parentHint*/);
    }
  }

大致可以猜出一二,這里是依托于activity之下碎片fragment來進(jìn)行周期的回調(diào);同理fragment也是這樣fragment.getChildFragmentManager();

 @NonNull
  private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
      @Nullable 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;
  }

上面代碼第一行: SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);

@NonNull
  RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm, @Nullable 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;
  }


 @Override
  public boolean handleMessage(Message message) {
    boolean handled = true;
    Object removed = null;
    Object key = null;
    switch (message.what) {
      case ID_REMOVE_FRAGMENT_MANAGER:
        android.app.FragmentManager fm = (android.app.FragmentManager) message.obj;
        key = fm;
        removed = pendingRequestManagerFragments.remove(fm);
        break;
      case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER:
        FragmentManager supportFm = (FragmentManager) message.obj;
        key = supportFm;
        removed = pendingSupportRequestManagerFragments.remove(supportFm);
        break;
      default:
        handled = false;
        break;
    }
    if (handled && removed == null && Log.isLoggable(TAG, Log.WARN)) {
      Log.w(TAG, "Failed to remove expected request manager fragment, manager: " + key);
    }
    return handled;
  }

在getRequestManagerFragment中通過創(chuàng)建RequestManagerFragment并且添加到activity中,同時(shí)把RequestManagerFragments從緩存隊(duì)列pendingRequestManagerFragments中移除,進(jìn)行加載;

然后繼續(xù)看supportFragmentGet:
獲取到SupportRequestManagerFragment,然后通過SupportRequestManagerFragment獲取requestManager: RequestManager requestManager = current.getRequestManager();如果為空則通過

factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);

進(jìn)行創(chuàng)建最后set到SupportRequestManagerFragment中;注意其參數(shù).current.getGlideLifecycle()其實(shí)就是這個(gè)接口來回調(diào)SupportRequestManagerFragment的周期方法進(jìn)而進(jìn)行周期的控制;

  1. 首先來看glide的相關(guān)配置:圖形屬性,

GlideApp.with(this)
.load(url)


首先來看url的加載:

#GlideApp
  @Override
  @NonNull
  @CheckResult
  public GlideRequest<TranscodeType> load(@Nullable String arg0) {
    return (GlideRequest<TranscodeType>) super.load(arg0);
  }

#Glide  --- 多種實(shí)現(xiàn)類
 @NonNull
  @Override
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
  }

  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
    return loadGeneric(uri);
  }

....


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


由以上代碼中可以看到load有很多實(shí)現(xiàn)類,最后都是在RequestBuilder中初始化參數(shù)model,在into的時(shí)候進(jìn)行加載;
接著看Glide對(duì)圖片屬性的支持:

GlideApp.with(this)
//.asBitmap() --- 對(duì)圖片格式的編碼轉(zhuǎn)化
//.asDrawable()
.asGif()
.miniThumb(100)
.placeholder(R.mipmap.ic_launcher_round) --- 占位圖
.error(R.mipmap.ele) ---- 錯(cuò)誤之后的顯示圖
.fitCenter() --- 圖片顯示樣式
//.fallback()當(dāng)請求圖片為null的時(shí)候

一般Glide通過一系列鏈?zhǔn)絹砼渲脠D片的屬性,和加載的屬性;當(dāng)然也可以通過RequestOption來自定義(把相關(guān)配置apply進(jìn)去),最后把RequestOption apply到RequstBuilder中;
舉一例.asGif():

#GlideApp
 @Override
  @NonNull
  @CheckResult
  public GlideRequest<GifDrawable> asGif() {
    return (GlideRequest<GifDrawable>) super.asGif();
  }

#Glide
  private static final RequestOptions DECODE_TYPE_GIF = decodeTypeOf(GifDrawable.class).lock();

 @NonNull
  @CheckResult
  public RequestBuilder<GifDrawable> asGif() {
    return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
  }


從以上代碼可以看到decodeTypeOf(GifDrawable.class).lock();轉(zhuǎn)化為一個(gè)GifDrawable之后apply到RequstBuilder中,看到這里是不是感覺RequstBuilder就是一個(gè)總指揮,主導(dǎo)Glide的大部分行為(如下 附decodeTypeOf的源碼)

  @NonNull
  @CheckResult
  public static RequestOptions decodeTypeOf(@NonNull Class<?> resourceClass) {
    return new RequestOptions().decode(resourceClass);
  }

當(dāng)這里我們對(duì)RequestOptions這個(gè)原型有了一定的了解;
當(dāng)然你可以參閱文章開頭的Glide v4官網(wǎng)來看其使用,慢慢體會(huì)這個(gè)思想;

  1. 最后看glide的加載與最終實(shí)現(xiàn):

GlideApp.with(this)
.load(url);
同樣由淺入深來看:

@NonNull
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
    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()) {
        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);
  }

首先是對(duì)圖片的現(xiàn)實(shí)樣式進(jìn)行設(shè)置,通過目標(biāo)getScaleType來同步requstoption的相關(guān)設(shè)置,繼續(xù)看:
glideContext.buildImageViewTarget(view, transcodeClass), null,requestOptions);
這里的三個(gè)參數(shù)分別是目標(biāo)target,targetListener,requestOptions;繼續(xù)看源碼:

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @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();
    Request request = buildRequest(target, targetListener, options);

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

其中:

 options = options.autoClone();
    Request request = buildRequest(target, targetListener, options);

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

以上代碼中通過對(duì)比當(dāng)前請求和之前的請求對(duì)比來去定是否復(fù)用(在圖片網(wǎng)絡(luò)框架中很常見);繼續(xù)看核心代碼:

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

接著看 requestManager.track(target, request);其他就是清楚和設(shè)置requst的代碼,一目了然:

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

注意在Glide中是可以設(shè)置優(yōu)先級(jí)的,在 targetTracker.track(target);中把目標(biāo)圖片統(tǒng)一通過targets來管理,而targets是Set集合是具有排序功能的;
繼續(xù)看 requestTracker.runRequest(request);源碼:

  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      pendingRequests.add(request);
    }
  }

到這里可以看到當(dāng)沒有onPause時(shí)候requst會(huì)開始加載,onPause時(shí)候加入緩存隊(duì)列等待;當(dāng)然我們看到了Glide所謂的周期管理:追根溯源:

1.在glide.with中提到activity中創(chuàng)建了SupportRequestManagerFragment,并通過傳入 current.getGlideLifecycle()來current.setRequestManager(requestManager);

2.在SupportRequestManagerFragment中通過會(huì)調(diào)lifecycle來監(jiān)聽其周期:
eg:

  @Override
  public void onStop() {
    super.onStop();
    lifecycle.onStop();
  }

3.然而這個(gè)lifecycle是ActivityFragmentLifecycle,在RequstManger的構(gòu)造中:
lifecycle.addListener(this);然后在周期的會(huì)調(diào)是實(shí)現(xiàn)方法中用targetTracker管理起來:
eg:

 # requstManger
  @Override
  public void onStop() {
    pauseRequests();
    targetTracker.onStop();
  }

   public void pauseRequests() {
    Util.assertMainThread();
    requestTracker.pauseRequests();
  }

#RequstTracker
 public void pauseRequests() {
    isPaused = true;
    for (Request request : Util.getSnapshot(requests)) {
      if (request.isRunning()) {
        request.pause();
        pendingRequests.add(request);
      }
    }
  }

ok~ 到了這里就明白了 之前講到

 public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      pendingRequests.add(request);
    }
  }

這里的周期判斷就已經(jīng)明了了,在Glide中SingleRequst比較常用,那么來看他的begin源碼:

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

以上代碼中Glide對(duì)加載狀態(tài)進(jìn)行了判斷,并且對(duì)其width和height進(jìn)行重新處理,讓然一些策略是不錯(cuò)的,比如:

  if (status == Status.COMPLETE) {
      onResourceReady(resource, DataSource.MEMORY_CACHE);
      return;
    }

 @SuppressWarnings("unchecked")
  @Override
  public void onResourceReady(Resource<?> resource, DataSource dataSource) {
    stateVerifier.throwIfRecycled();
    loadStatus = null;
    if (resource == null) {
      GlideException exception = new GlideException("Expected to receive a Resource<R> with an "
          + "object of " + transcodeClass + " inside, but instead got null.");
      onLoadFailed(exception);
      return;
    }

    Object received = resource.get();
    if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
      releaseResource(resource);
      GlideException exception = new GlideException("Expected to receive an object of "
          + transcodeClass + " but instead" + " got "
          + (received != null ? received.getClass() : "") + "{" + received + "} inside" + " "
          + "Resource{" + resource + "}."
          + (received != null ? "" : " " + "To indicate failure return a null Resource "
          + "object, rather than a Resource object containing null data."));
      onLoadFailed(exception);
      return;
    }

    if (!canSetResource()) {
      releaseResource(resource);
      // We can't put the status to complete before asking canSetResource().
      status = Status.COMPLETE;
      return;
    }

    onResourceReady((Resource<R>) resource, (R) received, dataSource);
  }

完成之后進(jìn)行資源釋放,并修改資源狀態(tài)等 ,這里不做詳盡的解釋(太多);ok 繼續(xù)回來看請求邏輯

  if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);
    } else {
      target.getSize(this);
    }

glide的請求在onSizeReady中:

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

    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并且傳入一堆參數(shù),主要是各種屬性的線程池,內(nèi)存狀態(tài),OPtion等;那么繼續(xù)看加載的實(shí)質(zhì)代碼:

public <R> LoadStatus load(
      .....參數(shù)省略) {
      
    ......

    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }

    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }

    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        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);

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logWithTimeAndKey("Started new load", startTime, key);
    }
    return new LoadStatus(cb, engineJob);
  }

OMG 代碼好長;首先看加扎起過程Glide并不會(huì)直接加載他是有兩次緩存的:LruCash和ActiveCash;在Glide中當(dāng)加載完畢,首先會(huì)將圖片短時(shí)間從LruCash中取出來放入ActiveCash,進(jìn)行臨時(shí)存儲(chǔ);所以首先從ActiveCash中獲取圖片

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

接著是從LruCash中獲取圖片:

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

最后才進(jìn)行加載:url:

 engineJob.addCallback(cb);
 engineJob.start(decodeJob);

注意Glide會(huì)有會(huì)調(diào)來監(jiān)聽加載圖片的每一個(gè)階段;比如我們在開發(fā)中會(huì)有這樣的場景:

     SimpleTarget<Drawable> into = GlideApp.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher_round)
                //開始請求
                .into(new SimpleTarget<Drawable>() {
                    @Override
                    public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
                        Log.i("glide_life", "onResourceReady");
                        mIv.setImageDrawable(resource);
                    }

                    @Override
                    public void setRequest(@Nullable Request request) {
                        super.setRequest(request);
                        Log.i("glide_life", "setRequest");

                    }

                     .....省略一些方法
                });

ok 繼續(xù)回歸網(wǎng)絡(luò)加載 engineJob.start(decodeJob);

 public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

由上面代碼 繼續(xù)看GlideExecutor下execute:

  public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

what? 為什么傳的是DecodeJob回來的是Runable,而且execute明顯是一些資源收尾的工作;好吧 DecodeJob 實(shí)現(xiàn)了Runable,并且在run方法中實(shí)現(xiàn)網(wǎng)絡(luò)請求:

@Override
  public void run() {
    DataFetcher<?> localFetcher = currentFetcher;
    try {
      if (isCancelled) {
        notifyFailed();
        return;
      }
      runWrapped();
    } catch (Throwable t) {
      if (Log.isLoggable(TAG, Log.DEBUG)) {
        Log.d(TAG, "DecodeJob threw unexpectedly"
            + ", isCancelled: " + isCancelled
            + ", stage: " + stage, t);
      }
      if (stage != Stage.ENCODE) {
        throwables.add(t);
        notifyFailed();
      }
      if (!isCancelled) {
        throw t;
      }
    } finally {
      // Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
      // close in all cases anyway.
      if (localFetcher != null) {
        localFetcher.cleanup();
      }
      TraceCompat.endSection();
    }
  }

在這里同樣通過狀態(tài)進(jìn)行請求;當(dāng)上請求cancle已經(jīng)cancel則 notifyFailed()(注意glide是可以取消網(wǎng)絡(luò)加載的),否則通過請求runWrapped()來請求網(wǎng)絡(luò);

 private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
        currentGenerator = getNextGenerator();
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }
private Stage getNextStage(Stage current) {
    switch (current) {
      case INITIALIZE:
        return diskCacheStrategy.decodeCachedResource()
            ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
      case RESOURCE_CACHE:
        return diskCacheStrategy.decodeCachedData()
            ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
      case DATA_CACHE:
        // Skip loading from source if the user opted to only retrieve the resource from cache.
        return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
      case SOURCE:
      case FINISHED:
        return Stage.FINISHED;
      default:
        throw new IllegalArgumentException("Unrecognized stage: " + current);
    }
  }

首先是獲取加載狀態(tài),然后在getNextGenerator()獲取圖片加載器;

private DataFetcherGenerator getNextGenerator() {
    switch (stage) {
      case RESOURCE_CACHE:
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }

  private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    while (!isCancelled && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

      if (stage == Stage.SOURCE) {
        reschedule();
        return;
      }
    }

    if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
      notifyFailed();
    }
  }

在Glide中有3種加載器(暫時(shí)這樣定義)DataCacheGenerator,SourceGenerator,ResourceCacheGenerator
基于以上3鐘然后在runGenerators()中進(jìn)行真正的加載:currentGenerator.startNext()
下面以SourceGenerator為例

  @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    sourceCacheGenerator = null;

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

核心加載邏輯: loadData.fetcher.loadData(helper.getPriority(), this);

盡可能詳盡的對(duì)glide 就行剖析.重點(diǎn)是思想.希望對(duì)大家有所助益

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市场斑,隨后出現(xiàn)的幾起案子糠睡,更是在濱河造成了極大的恐慌挽鞠,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狈孔,死亡現(xiàn)場離奇詭異信认,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)均抽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門嫁赏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人油挥,你說我怎么就攤上這事潦蝇】畎荆” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵攘乒,是天一觀的道長贤牛。 經(jīng)常有香客問我,道長则酝,這世上最難降的妖魔是什么殉簸? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮堤魁,結(jié)果婚禮上喂链,老公的妹妹穿的比我還像新娘返十。我一直安慰自己妥泉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布洞坑。 她就那樣靜靜地躺著盲链,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迟杂。 梳的紋絲不亂的頭發(fā)上刽沾,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天,我揣著相機(jī)與錄音排拷,去河邊找鬼侧漓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛监氢,可吹牛的內(nèi)容都是我干的布蔗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼浪腐,長吁一口氣:“原來是場噩夢啊……” “哼纵揍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起议街,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤泽谨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后特漩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吧雹,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年涂身,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吮炕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡访得,死狀恐怖龙亲,靈堂內(nèi)的尸體忽然破棺而出陕凹,到底是詐尸還是另有隱情驾孔,我是刑警寧澤盗痒,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布翘魄,位于F島的核電站帝嗡,受9級(jí)特大地震影響纠亚,放射性物質(zhì)發(fā)生泄漏蹦玫。R本人自食惡果不足惜奥秆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一阻肿、第九天 我趴在偏房一處隱蔽的房頂上張望谈竿。 院中可真熱鬧团驱,春花似錦、人聲如沸空凸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呀洲。三九已至紊选,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間道逗,已是汗流浹背兵罢。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留滓窍,地道東北人卖词。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像吏夯,于是被迫代替她去往敵國和親此蜈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容