跳转至

Glide源码分析

本文保留 with/load/into 的历史阅读笔记,新增的 设计模式分析与 UML 类图 基于 Glide 4.12.0,包含九种模式的角色、协作过程与源码引用。

Glide的使用非常简单只需要调用with、load into三个方法。

1
2
3
 GlideApp.with(this)
        .load(url)
        .into(imageView);

接下来,我们依次分析这三个方法。

with()

//Glide.java
public static RequestManager with(@NonNull Activity activity) {
  //先获取RequestManagerRetriever对象
  //调用RequestManagerRetriever的get方法获取RequestManager
  return getRetriever(activity).get(activity); 
}
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
  // Context could be null for other reasons (ie the user passes in null), but in practice it will
  // only occur due to errors with the Fragment lifecycle.
  Preconditions.checkNotNull(
      context,
      "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
          + "returns null (which usually occurs when getActivity() is called before the Fragment "
          + "is attached or after the Fragment is destroyed).");

  return Glide.get(context).getRequestManagerRetriever();
}

get()

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

ApiGlideModule

ApiGlideModule定义了在应用程序中初始化 Glide 时要使用的一系列依赖关系和选项。

1
2
3
4
5
6
//GeneratedAppGlideModuleImpl
 @Override
 @NonNull
 GeneratedRequestManagerFactory getRequestManagerFactory() {
   return new GeneratedRequestManagerFactory();
 }

checkAndInitializeGlide()

@GuardedBy("Glide.class")
private static void checkAndInitializeGlide(
    @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
    // 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, generatedAppGlideModule);
    isInitializing = false;
}

initializeGlide()

1
2
3
4
5
@GuardedBy("Glide.class")
private static void initializeGlide(
    @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
    initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
}
  @GuardedBy("Glide.class")
  @SuppressWarnings("deprecation")
  private static void initializeGlide(
      @NonNull Context context,
      @NonNull GlideBuilder builder,
      @Nullable GeneratedAppGlideModule annotationGeneratedModule) {
    Context applicationContext = context.getApplicationContext();
    List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
    if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
      //解析ManifestParser 老的Glide版本需要在清单文件中注册GlideModule
      manifestModules = new ManifestParser(applicationContext).parse();
    }

    if (annotationGeneratedModule != null
        && !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
      Set<Class<?>> excludedModuleClasses = annotationGeneratedModule.getExcludedModuleClasses();
      Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
      while (iterator.hasNext()) {
        com.bumptech.glide.module.GlideModule current = iterator.next();
        if (!excludedModuleClasses.contains(current.getClass())) {
          continue;
        }
        if (Log.isLoggable(TAG, Log.DEBUG)) {
          Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
        }
        iterator.remove();
      }
    }

    if (Log.isLoggable(TAG, Log.DEBUG)) {
      for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
        Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
      }
    }
    //获取RequestManagerFactory即GeneratedRequestManagerFactory
    RequestManagerRetriever.RequestManagerFactory factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManagerFactory()
            : null;
    //为GlideBuilder设置RequestManagerFactory
    builder.setRequestManagerFactory(factory);
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      module.applyOptions(applicationContext, builder);
    }
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.applyOptions(applicationContext, builder);
    }
    //调用build方法创建Glide对象
    Glide glide = builder.build(applicationContext);
    for (com.bumptech.glide.module.GlideModule module : manifestModules) {
      try {
        module.registerComponents(applicationContext, glide, glide.registry);
      } catch (AbstractMethodError e) {
        throw new IllegalStateException(
            "Attempting to register a Glide v3 module. If you see this, you or one of your"
                + " dependencies may be including Glide v3 even though you're using Glide v4."
                + " You'll need to find and remove (or update) the offending dependency."
                + " The v3 module name is: "
                + module.getClass().getName(),
            e);
      }
    }
    if (annotationGeneratedModule != null) {
      annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
    }
    applicationContext.registerComponentCallbacks(glide);
    Glide.glide = glide;
  }

GlideBuilder

  @NonNull
  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();
    }
    //除了ArrayPool之外每个缓存都有两个版本。
    //LruBitmapPool BitmapPoolAdapter
    //LruResourceCache MemoryCacheAdapter
    //DiskLruCacheWrapper DiskCacheAdapter
    //当内存不足的时候调用XXAdapter,put方法里什么也不做
    // 正常调用LruXX
    //BitmapPool
    if (bitmapPool == null) {
      int size = memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) {
        bitmapPool = new LruBitmapPool(size);
      } else {
        bitmapPool = new BitmapPoolAdapter();
      }
    }
    //ArrayPool
    if (arrayPool == null) {
      arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
    }
   //MemoryCache
    if (memoryCache == null) {
      memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
    }
    //DiskCacheFactory
    if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
    }
    //创建Engine
    if (engine == null) {
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(),//无限制缓存池
              animationExecutor,
              isActiveResourceRetentionAllowed);
    }

    if (defaultRequestListeners == null) {
      defaultRequestListeners = Collections.emptyList();
    } else {
      defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
    }
    //创建RequestManagerRetriever
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(
            requestManagerFactory, waitForFirstFrameBeforeEnablingHardwareBitmaps);

    boolean blockHardwareBitmaps =
        waitForFirstFrameBeforeEnablingHardwareBitmaps || waitForCallBeforeEnablingHardwareBitmaps;
    //调用Glide构造函数创建Glide对象
    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptionsFactory,
        defaultTransitionOptions,
        defaultRequestListeners,
        isLoggingRequestOriginsEnabled,
        isImageDecoderEnabledForBitmaps,
        blockHardwareBitmaps,
        manualOverrideHardwareBitmapMaxFdCount);
  }

GlideExecutor

在build()中一共创建了4个线程池

newDiskCacheExecutor()创建磁盘缓存的线程池

1
2
3
4
5
6
7
8
9
  private static final int DEFAULT_DISK_CACHE_EXECUTOR_THREADS = 1;
  public static GlideExecutor newDiskCacheExecutor() {
    return newDiskCacheBuilder().build();
  }
  public static GlideExecutor.Builder newDiskCacheBuilder() {
    return new GlideExecutor.Builder(/*preventNetworkOperations=*/ true)
        .setThreadCount(DEFAULT_DISK_CACHE_EXECUTOR_THREADS) //线程数1
        .setName(DEFAULT_DISK_CACHE_EXECUTOR_NAME);
  }

其余三个线程池都是负责下载和解码的newAnimationBuilder是用来处理gif的。

public final class GlideExecutor implements ExecutorService {
  private static final int MAXIMUM_AUTOMATIC_THREAD_COUNT = 4;

  public static GlideExecutor newSourceExecutor() {
    return newSourceBuilder().build();
  }
  public static GlideExecutor.Builder newSourceBuilder() {
    return new GlideExecutor.Builder(/*preventNetworkOperations=*/ false)
        .setThreadCount(calculateBestThreadCount())
        .setName(DEFAULT_SOURCE_EXECUTOR_NAME);
  }
  //计算最佳的线程数量
  public static int calculateBestThreadCount() {
    if (bestThreadCount == 0) {
      //cpu内核数量和4取最小值
      bestThreadCount =
          Math.min(MAXIMUM_AUTOMATIC_THREAD_COUNT, RuntimeCompat.availableProcessors());
    }
    return bestThreadCount;
  }
}
  public static GlideExecutor.Builder newAnimationBuilder() {
    int bestThreadCount = calculateBestThreadCount();
    // We don't want to add a ton of threads running animations in parallel with our source and
    // disk cache executors. Doing so adds unnecessary CPU load and can also dramatically increase
    // our maximum memory usage. Typically one thread is sufficient here, but for higher end devices
    // with more cores, two threads can provide better performance if lots of GIFs are showing at
    // once.
    //我们不希望增加大量线程来并行运行动画,我们的源代码和磁盘缓存执行器。
    //这样做增加了不必要的CPU负载,也会大大增加了我们的最大内存使用量。
    //通常情况下,一个线程就足够了,但对于更高端的设备来说。
    //如果有更多的核心,两个线程可以提供更好的性能,如果大量的GIF显示一次。
    int maximumPoolSize = bestThreadCount >= 4 ? 2 : 1;

    return new GlideExecutor.Builder(/*preventNetworkOperations=*/ true)
        .setThreadCount(maximumPoolSize)
        .setName(DEFAULT_ANIMATION_EXECUTOR_NAME);
  }

  /** Shortcut for calling {@link Builder#build()} on {@link #newAnimationBuilder()}. */
  public static GlideExecutor newAnimationExecutor() {
    return newAnimationBuilder().build();
  }
  public static GlideExecutor newUnlimitedSourceExecutor() {
    return new GlideExecutor(
        new ThreadPoolExecutor(
            0,
            Integer.MAX_VALUE,
            KEEP_ALIVE_TIME_MS,
            TimeUnit.MILLISECONDS,
            new SynchronousQueue<Runnable>(),
            new DefaultThreadFactory(
                DEFAULT_SOURCE_UNLIMITED_EXECUTOR_NAME, UncaughtThrowableStrategy.DEFAULT, false)));
  }

这三个线程池选用哪个呢?

1
2
3
4
5
6
  //EngineJob.java
  private GlideExecutor getActiveSourceExecutor() {
    return useUnlimitedSourceGeneratorPool
        ? sourceUnlimitedExecutor
        : (useAnimationPool ? animationExecutor : sourceExecutor);
  }

useUnlimitedSourceGeneratorsPool和useAnimationPool可以通过BaseRequestOptions进行配置。

  private boolean useUnlimitedSourceGeneratorsPool;
  private boolean useAnimationPool;
  @NonNull
  @CheckResult
  public T useAnimationPool(boolean flag) {
    if (isAutoCloneEnabled) {
      return clone().useAnimationPool(flag);
    }

    useAnimationPool = flag;
    fields |= USE_ANIMATION_POOL;

    return selfOrThrowIfLocked();
  }

useAnimationPool默认不需要配置。系统默认会在处理gif的时候设置为true。

  //GifFrameLoader.java
  private static RequestBuilder<Bitmap> getRequestBuilder(
      RequestManager requestManager, int width, int height) {
    return requestManager
        .asBitmap()
        .apply(
            diskCacheStrategyOf(DiskCacheStrategy.NONE)
                .useAnimationPool(true)
                .skipMemoryCache(true)
                .override(width, height));
  }

MemorySizeCalculator

  public static final class Builder {
    @VisibleForTesting static final int MEMORY_CACHE_TARGET_SCREENS = 2;

    /**
     * On Android O+, we use {@link android.graphics.Bitmap.Config#HARDWARE} for all reasonably
     * sized images unless we're creating thumbnails for the first time. As a result, the Bitmap
     * pool is much less important on O than it was on previous versions.
     */
    static final int BITMAP_POOL_TARGET_SCREENS =
        Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 4 : 1;

    static final float MAX_SIZE_MULTIPLIER = 0.4f;
    static final float LOW_MEMORY_MAX_SIZE_MULTIPLIER = 0.33f;
    // 4MB.
    static final int ARRAY_POOL_SIZE_BYTES = 4 * 1024 * 1024;

    @Synthetic final Context context;

    // Modifiable (non-final) for testing.
    @Synthetic ActivityManager activityManager;
    @Synthetic ScreenDimensions screenDimensions;

    @Synthetic float memoryCacheScreens = MEMORY_CACHE_TARGET_SCREENS;
    @Synthetic float bitmapPoolScreens = BITMAP_POOL_TARGET_SCREENS;
    @Synthetic float maxSizeMultiplier = MAX_SIZE_MULTIPLIER;
    @Synthetic float lowMemoryMaxSizeMultiplier = LOW_MEMORY_MAX_SIZE_MULTIPLIER;
    @Synthetic int arrayPoolSizeBytes = ARRAY_POOL_SIZE_BYTES;
 }
// Package private to avoid PMD warning.
  MemorySizeCalculator(MemorySizeCalculator.Builder builder) {
    this.context = builder.context;
    //4M 低内存设备2M
    arrayPoolSize =
        isLowMemoryDevice(builder.activityManager)
            ? builder.arrayPoolSizeBytes / LOW_MEMORY_BYTE_ARRAY_POOL_DIVISOR
            : builder.arrayPoolSizeBytes;
    //计算最大大小
    int maxSize =
        getMaxSize(
            builder.activityManager, builder.maxSizeMultiplier, builder.lowMemoryMaxSizeMultiplier);

    int widthPixels = builder.screenDimensions.getWidthPixels();
    int heightPixels = builder.screenDimensions.getHeightPixels();
    //计算一张格式为 ARGB_8888 ,大小为屏幕大小的图片的占用内存大小
    //BYTES_PER_ARGB_8888_PIXEL 值为 4
    int screenSize = widthPixels * heightPixels * BYTES_PER_ARGB_8888_PIXEL;
    //BitmapPool大小
    //BitmapPool和MemoryCache的大小依赖当前屏幕分辨率
    int targetBitmapPoolSize = Math.round(screenSize * builder.bitmapPoolScreens);
    //MemoryCache大小 
    int targetMemoryCacheSize = Math.round(screenSize * builder.memoryCacheScreens);
    int availableSize = maxSize - arrayPoolSize;
    //小于可用大小 按照计算的值分配
    if (targetMemoryCacheSize + targetBitmapPoolSize <= availableSize) {
      memoryCacheSize = targetMemoryCacheSize;
      bitmapPoolSize = targetBitmapPoolSize;
    } else {
      //将可用的分配
      float part = availableSize / (builder.bitmapPoolScreens + builder.memoryCacheScreens);
      memoryCacheSize = Math.round(part * builder.memoryCacheScreens);
      bitmapPoolSize = Math.round(part * builder.bitmapPoolScreens);
    }
  }
1
2
3
4
5
6
7
  private static int getMaxSize(
      ActivityManager activityManager, float maxSizeMultiplier, float lowMemoryMaxSizeMultiplier) {
    final int memoryClassBytes = activityManager.getMemoryClass() * 1024 * 1024;
    final boolean isLowMemoryDevice = isLowMemoryDevice(activityManager);
    return Math.round(
        memoryClassBytes * (isLowMemoryDevice ? lowMemoryMaxSizeMultiplier : maxSizeMultiplier));
  }

磁盘缓存

public final class InternalCacheDiskCacheFactory extends DiskLruCacheFactory {

  public InternalCacheDiskCacheFactory(Context context) {
    this(
        context,
        DiskCache.Factory.DEFAULT_DISK_CACHE_DIR,
        DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE);
  }

  public InternalCacheDiskCacheFactory(Context context, long diskCacheSize) {
    this(context, DiskCache.Factory.DEFAULT_DISK_CACHE_DIR, diskCacheSize);
  }

  public InternalCacheDiskCacheFactory(
      final Context context, final String diskCacheName, long diskCacheSize) {
    super(
        new CacheDirectoryGetter() {
          @Override
          public File getCacheDirectory() {
            File cacheDirectory = context.getCacheDir();
            if (cacheDirectory == null) {
              return null;
            }
            if (diskCacheName != null) {
              return new File(cacheDirectory, diskCacheName);
            }
            return cacheDirectory;
          }
        },
        diskCacheSize);
  }
}
 interface Factory {
    /** 250 MB of cache. */
    int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024;

    String DEFAULT_DISK_CACHE_DIR = "image_manager_disk_cache";

    /** Returns a new disk cache, or {@code null} if no disk cache could be created. */
    @Nullable
    DiskCache build();
  }

get()

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

Lifecycle

Glide会添加一个透明的Fragment,当Fragment执行生命周期方法时,回调Lifecycle注册的LifecycleListener。

@Deprecated
  @NonNull
  private RequestManager fragmentGet(
      @NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint,
      boolean isParentVisible) {
    //创建RequestManagerFragment
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      //将Lifecycle和RequestManagerTreeNode传递给RequestManager
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      // This is a bit of hack, we're going to start the RequestManager, but not the
      // corresponding Lifecycle. It's safe to start the RequestManager, but starting the
      // Lifecycle might trigger memory leaks. See b/154405040
      if (isParentVisible) {
        requestManager.onStart();
      }
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
  @SuppressWarnings("deprecation")
  @NonNull
  private RequestManagerFragment getRequestManagerFragment(
      @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      //从Map中获取RequestManagerFragment
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        //创建ReqeustManagerFragment
        //创建Fragment的时候创建Lifecycle
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingRequestManagerFragments.put(fm, current);
        //添加fragment
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }
1
2
3
  public RequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }

LifecycleListener

RequestManager

在RequestManager中将当前对象和DefaultConnectivityMonitor和注册到Lifecycle。

  private final Runnable addSelfToLifecycle =
      new Runnable() {
        @Override
        public void run() {
          lifecycle.addListener(RequestManager.this);
        }
      };
  private final ConnectivityMonitor connectivityMonitor;
  // Adding default listeners should be much less common than starting new requests. We want
  // some way of making sure that requests don't mutate our listeners without creating a new copy of
  // the list each time a request is started.
  private final CopyOnWriteArrayList<RequestListener<Object>> defaultRequestListeners;

  @GuardedBy("this")
  private RequestOptions requestOptions;

  private boolean pauseAllRequestsOnTrimMemoryModerate;

  public RequestManager(
      @NonNull Glide glide,
      @NonNull Lifecycle lifecycle,
      @NonNull RequestManagerTreeNode treeNode,
      @NonNull Context context) {
    this(
        glide,
        lifecycle,
        treeNode,
        new RequestTracker(),
        glide.getConnectivityMonitorFactory(),
        context);
  }

  // Our usage is safe here.
  @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
  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()) {
      Util.postOnUiThread(addSelfToLifecycle);
    } else {
      lifecycle.addListener(this);
    }
    //添加
    lifecycle.addListener(connectivityMonitor);

    defaultRequestListeners =
        new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
    setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());

    glide.registerRequestManager(this);
  }

load()

通过with()方法返回了一个RequestManager对象,所以load()方法调用的是RequestManager的load()方法。

@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) {
    //创建RequestBuilder
  return new RequestBuilder<>(glide, this, resourceClass, context);
}

RequestBuilder

into()

load()比较简单就是创建一个RequestBuilder对象。into()方法就是调用RequestBuilder的into()。

 @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());
  }
  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 request = buildRequest(target, targetListener, options, callbackExecutor);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      // 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);
    //追踪Request
    requestManager.track(target, request);

    return target;
  }

obtainRequest()

  private Request obtainRequest(
      Object requestLock,
      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,
        requestLock,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory(),
        callbackExecutor);
  }

Request

整体流程

第一次加载网络图片的编解码过程

缓存过程

//从缓存中获取
@Nullable
private EngineResource<?> loadFromMemory(
    EngineKey key, boolean isMemoryCacheable, long startTime) {
  //内存缓存不可用直接返回null
  if (!isMemoryCacheable) {
    return null;
  }
  //先从弱引用中获取,如果获取不到则从LruResourceCache中获取缓存
  EngineResource<?> active = loadFromActiveResources(key);
  if (active != null) {
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Loaded resource from active resources", startTime, key);
    }
    return active;
  }

  EngineResource<?> cached = loadFromCache(key);
  if (cached != null) {
    if (VERBOSE_IS_LOGGABLE) {
      logWithTimeAndKey("Loaded resource from cache", startTime, key);
    }
    return cached;
  }
  return null;
}
@Nullable
private EngineResource<?> loadFromActiveResources(Key key) {
  //从弱引用中获取
  EngineResource<?> active = activeResources.get(key);
  if (active != null) {
    active.acquire();
  }
  return active;
}
private EngineResource<?> loadFromCache(Key key) {
  EngineResource<?> cached = getEngineResourceFromCache(key);
  if (cached != null) {
    cached.acquire();
    activeResources.activate(key, cached);
  }
  return cached;
}
private EngineResource<?> getEngineResourceFromCache(Key key) {
  //从LruResourceCache中获取缓存
  Resource<?> cached = cache.remove(key);
  final EngineResource<?> result;
  if (cached == null) {
    result = null;
  } else if (cached instanceof EngineResource) {
    // Save an object allocation if we've cached an EngineResource (the typical case).
    result = (EngineResource<?>) cached;
  } else {
    result =
        new EngineResource<>(
            cached, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
  }
  return result;
}
//写入缓存
@Override
public synchronized void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
  activeResources.deactivate(cacheKey);
  if (resource.isMemoryCacheable()) {
    cache.put(cacheKey, resource);
  } else {
    resourceRecycler.recycle(resource);
  }
}

ModelLoader

ModelLoader类负责将model转换为data。model就是我们在调用load方法传入的值。

getLoadData()

  //
  List<LoadData<?>> getLoadData() {
    if (!isLoadDataSet) {
      isLoadDataSet = true; //获取成功之后设置为true 避免多次获取
      loadData.clear();
      //根据Model获取ModelLoader
      List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
      //noinspection ForLoopReplaceableByForEach to improve perf
      for (int i = 0, size = modelLoaders.size(); i < size; i++) {
        ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
        LoadData<?> current = modelLoader.buildLoadData(model, width, height, options);
        if (current != null) {
          loadData.add(current);
        }
      }
    }
    return loadData;
  }

getModelLoaders()

1
2
3
4
  @NonNull
  public <Model> List<ModelLoader<Model, ?>> getModelLoaders(@NonNull Model model) {
    return modelLoaderRegistry.getModelLoaders(model);
  }
  @NonNull
  public <A> List<ModelLoader<A, ?>> getModelLoaders(@NonNull A model) {
    List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
    if (modelLoaders.isEmpty()) {
      throw new NoModelLoaderAvailableException(model);
    }
    int size = modelLoaders.size();
    boolean isEmpty = true;
    List<ModelLoader<A, ?>> filteredLoaders = Collections.emptyList();
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0; i < size; i++) {
      ModelLoader<A, ?> loader = modelLoaders.get(i);
      if (loader.handles(model)) {
        if (isEmpty) {
          filteredLoaders = new ArrayList<>(size - i);
          isEmpty = false;
        }
         //根据ModelLoader的handles方法,过滤掉不匹配的
        //假设传入的是url,则过滤掉DataUrlLoader
        filteredLoaders.add(loader);
      }
    }
    if (filteredLoaders.isEmpty()) {
      throw new NoModelLoaderAvailableException(model, modelLoaders);
    }
    return filteredLoaders;
  }
  @NonNull
  private synchronized <A> List<ModelLoader<A, ?>> getModelLoadersForClass(
      @NonNull Class<A> modelClass) {
    //从缓存中取
    List<ModelLoader<A, ?>> loaders = cache.get(modelClass);
    if (loaders == null) {
      //调用MultiModelLoaderFactory的build方法
      loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
      cache.put(modelClass, loaders);
    }
    return loaders;
  }
  @NonNull
  synchronized <Model> List<ModelLoader<Model, ?>> build(@NonNull Class<Model> modelClass) {
    try {
      List<ModelLoader<Model, ?>> loaders = new ArrayList<>();
      for (Entry<?, ?> entry : entries) {
        // Avoid stack overflow recursively creating model loaders by only creating loaders in
        // recursive requests if they haven't been created earlier in the chain. For example:
        // A Uri loader may translate to another model, which in turn may translate back to a Uri.
        // The original Uri loader won't be provided to the intermediate model loader, although
        // other Uri loaders will be.
        if (alreadyUsedEntries.contains(entry)) {
          continue;
        }
        //根据ModelClass进行判断
        if (entry.handles(modelClass)) {
          alreadyUsedEntries.add(entry);
          //调用Factory创建Loader
          loaders.add(this.<Model, Object>build(entry));
          alreadyUsedEntries.remove(entry);
        }
      }
      return loaders;
    } catch (Throwable t) {
      alreadyUsedEntries.clear();
      throw t;
    }
  }
//StringLoader先将String转化为Uri
//通过MultiModelLoaderFactory获取一个MultiModelLoader对象
//内部调用的MultiModelLoader
public static class StreamFactory implements ModelLoaderFactory<String, InputStream> {

    @NonNull
    @Override
    public ModelLoader<String, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
      return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));
    }

    @Override
    public void teardown() {
      // Do nothing.
    }
}
  @NonNull
  public synchronized <Model, Data> ModelLoader<Model, Data> build(
      @NonNull Class<Model> modelClass, @NonNull Class<Data> dataClass) {
    try {
      List<ModelLoader<Model, Data>> loaders = new ArrayList<>();
      boolean ignoredAnyEntries = false;
      for (Entry<?, ?> entry : entries) {
        // Avoid stack overflow recursively creating model loaders by only creating loaders in
        // recursive requests if they haven't been created earlier in the chain. For example:
        // A Uri loader may translate to another model, which in turn may translate back to a Uri.
        // The original Uri loader won't be provided to the intermediate model loader, although
        // other Uri loaders will be.
        if (alreadyUsedEntries.contains(entry)) {
          ignoredAnyEntries = true;
          continue;
        }
        if (entry.handles(modelClass, dataClass)) {
          alreadyUsedEntries.add(entry);
          loaders.add(this.<Model, Data>build(entry));
          alreadyUsedEntries.remove(entry);
        }
      }
      //如果存在多个就构建成一个MultiModelLoader
      if (loaders.size() > 1) {
        return factory.build(loaders, throwableListPool);
      } else if (loaders.size() == 1) {
        return loaders.get(0);
      } else {
        // Avoid crashing if recursion results in no loaders available. The assertion is supposed to
        // catch completely unhandled types, recursion may mean a subtype isn't handled somewhere
        // down the stack, which is often ok.
        if (ignoredAnyEntries) {
          return emptyModelLoader();
        } else {
          throw new NoModelLoaderAvailableException(modelClass, dataClass);
        }
      }
    } catch (Throwable t) {
      alreadyUsedEntries.clear();
      throw t;
    }
  }
1
2
3
4
5
6
7
8
  static class Factory {
    @NonNull
    public <Model, Data> MultiModelLoader<Model, Data> build(
        @NonNull List<ModelLoader<Model, Data>> modelLoaders,
        @NonNull Pool<List<Throwable>> throwableListPool) {
      return new MultiModelLoader<>(modelLoaders, throwableListPool);
    }
  }

加载到内存的图片大小

默认大小为ImageView的大小。设置了override,则是设置的大小。如果设置值为Target.SIZE_ORIGINAL,则使用图片原始大小。

//SingleRequest begin方法
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
    onSizeReady(overrideWidth, overrideHeight);
} else {
    target.getSize(this);
}
//ViewTarget getSize方法
public void getSize(@NonNull SizeReadyCallback cb) {
    sizeDeterminer.getSize(cb);
}
//SizeDeterminer 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);
    }
}
//CustomTarget默认是原图大小
public CustomTarget() {
    this(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
}
//Downsampler decodeFromWrappedStreams方法
//获取图片的原始宽高
int[] sourceDimensions = getDimensions(is, options, callbacks, bitmapPool);
int sourceWidth = sourceDimensions[0];
int sourceHeight = sourceDimensions[1];
//如果设置Target.SIZE_ORIGINAL 则为原始宽高
int targetWidth = requestedWidth == Target.SIZE_ORIGINAL ? sourceWidth : requestedWidth;
int targetHeight = requestedHeight == Target.SIZE_ORIGINAL ? sourceHeight : requestedHeight;

设计模式分析

本节基于 Glide 4.12.0,固定源码提交为 384617791a97f3d2f3052e0b63bd4d971da92f7d。前面的历史摘录保留原貌,可能与该版本存在差异;以下角色和调用关系以固定源码为准。

阅读时可以沿着一次请求理解这些模式:Glide.get() 获取共享基础设施,RequestBuilder 配置并组装请求树,RequestManager 根据生命周期管理请求,加载器将输入适配为数据,缓存策略决定读写路径,转换模板处理图片,资源包装器管理使用和回收。

模式 Glide 中的例子 解决的问题
单例 Glide.get() 共享引擎、缓存、组件注册表等基础设施
建造者 GlideBuilder、RequestBuilder 分步配置复杂对象并集中组装
工厂方法 ModelLoaderFactory.build() 将具体加载器的创建交给工厂实现
策略 DiskCacheStrategy 替换磁盘缓存决策
观察者 ActivityFragmentLifecycle、RequestManager 将生命周期事件传给请求管理器
组合 ThumbnailRequestCoordinator、ErrorRequestCoordinator 用统一接口管理单个请求和请求树
模板方法 BitmapTransformation 固定转换流程,让子类实现具体算法
装饰者 EngineResource 为资源增加引用计数与回收控制
适配器 StringLoader、UrlUriLoader 转换输入模型,复用已有加载能力

下列类图仅展示相关成员,通常省略泛型参数、注解和无关方法;实线箭头表示持有关联,虚线箭头表示调用或创建依赖,空心三角表示继承或接口实现。图中角色描述是对源码职责的解释,不表示 Glide 为每个角色都定义了同名基类。

单例:共享 Glide 基础设施

加载图片需要执行器、内存缓存、位图池和注册表。如果每次请求都重新创建这些对象,既浪费资源,也无法有效复用缓存。正常运行时,Glide.get(context) 返回同一个进程内共享实例。

角色 实际类型或成员 职责
单例对象 Glide 持有 Engine、MemoryCache、BitmapPool、Registry 等
实例引用 Glide.glide private static volatile 字段,保存初始化后的实例
统一访问点 Glide.get(Context) 延迟初始化并返回实例
作用域入口 RequestManagerRetriever 为不同上下文获取相应的 RequestManager
classDiagram
    class Glide {
        -Glide glide$
        +get(context) Glide$
        +getRequestManagerRetriever() RequestManagerRetriever
    }
    class RequestManagerRetriever {
        +get(context) RequestManager
    }
    Glide --> RequestManagerRetriever : requestManagerRetriever
    Glide --> Engine : engine
    Glide --> MemoryCache : memoryCache
    Glide --> BitmapPool : bitmapPool
    RequestManagerRetriever ..> RequestManager : 按作用域获取

get() 先检查静态字段;为空时进入 synchronized (Glide.class),再次检查后初始化。volatile 配合双重检查锁,使其他线程能够正确看到发布后的对象。初始化使用 application context,经过模块配置、GlideBuilder.build()、组件注册等步骤,最后赋值给 Glide.glide。

这里要区分 共享 Glide 和 与生命周期关联的 RequestManager:对 Activity、Fragment 等调用 with(),得到的管理器受对应作用域约束,不能据此说所有 RequestManager 都是同一个单例。该版本还提供测试用初始化、销毁入口,且 Glide 构造器是包可见;“单例”描述的是常规访问和生命周期管理方式,并不意味着任何场景下都绝不可能重建实例。

源码:Glide 的实例访问与初始化、RequestManagerRetriever。

建造者:配置与请求组装

Glide 中有两个层次的建造过程。GlideBuilder 组装库的全局基础设施;RequestBuilder 收集一次加载的模型、选项以及 thumbnail/error 配置,再组装实际的 Request。

角色 实际类型 职责
全局建造者 GlideBuilder 设置缓存、池、执行器等,补齐默认值并创建 Glide
全局产品 Glide 保存组装后的组件并提供加载入口
请求建造者 RequestBuilder 保存模型与选项,递归创建请求及协调器
公共配置基类 BaseRequestOptions 提供尺寸、变换、磁盘缓存策略等配置
请求产品 Request、SingleRequest 等 承担启动、暂停、清理和状态查询
classDiagram
    class GlideBuilder {
        +setMemoryCache(memoryCache) GlideBuilder
        ~build(context) Glide
    }
    class BaseRequestOptions {
        <<abstract>>
        +diskCacheStrategy(strategy)
    }
    class RequestBuilder {
        +load(model) RequestBuilder
        +thumbnail(builder) RequestBuilder
        +error(builder) RequestBuilder
        +into(target) Target
        -buildRequest() Request
    }
    class Request {
        <<interface>>
        +begin()
        +clear()
    }
    GlideBuilder ..> Glide : 创建
    BaseRequestOptions <|-- RequestBuilder
    RequestBuilder ..> Request : 组装
    RequestBuilder --> RequestManager : requestManager
    RequestManager ..> Request : track
    Request <|.. SingleRequest

一次典型调用可以拆成三步:

  1. load(model) 保存模型并标记已配置,尚未开始读取图片。
  2. into(target) 调用 buildRequest(),按配置生成 SingleRequest 或包含协调器的请求树。
  3. 新请求绑定到 Target 后交给 RequestManager.track(),再由 RequestTracker 根据暂停状态启动或暂存。

into() 也可能复用 Target 上等价的旧请求:旧请求未运行时调用 begin(),然后直接返回 Target。它的返回值是 Target,RequestBuilder 本身也没有实现 Request。

判断建造者的依据是“收集配置并集中组装复杂对象”,不仅是 API 可以链式调用。这个实现没有必要硬套一个独立的 Director 类。图中的 buildRequest() 省略了真实参数;GlideBuilder.build(Context) 则是包可见方法。

源码:GlideBuilder 的组装过程、loadGeneric、into 与请求绑定、递归构建请求、RequestTracker.runRequest。

工厂方法:创建不同的 ModelLoader

字符串、Uri、文件和网络地址需要不同的加载器。注册表只需要保存模型类型、数据类型和工厂,不必直接依赖每个加载器的构造细节。

角色 实际类型或方法 职责
工厂接口 ModelLoaderFactory<Model, Data> 声明创建加载器的 build(multiFactory)
具体工厂 StringLoader.StreamFactory 创建从 String 获取 InputStream 的加载器,并取得 Uri 委托加载器
具体工厂 HttpGlideUrlLoader.Factory 创建网络加载器,传入共享的模型缓存
产品接口 ModelLoader<Model, Data> 判断能否处理模型,构建 LoadData
工厂调用与组装 MultiModelLoaderFactory 按注册项查找工厂,必要时组合多个产品
classDiagram
    class ModelLoaderFactory {
        <<interface>>
        +build(multiFactory) ModelLoader
        +teardown()
    }
    class ModelLoader {
        <<interface>>
        +handles(model) boolean
        +buildLoadData(model, width, height, options) LoadData
    }
    class StringFactory["StringLoader.StreamFactory"]
    class HttpFactory["HttpGlideUrlLoader.Factory"]
    ModelLoaderFactory <|.. StringFactory
    ModelLoaderFactory <|.. HttpFactory
    StringFactory ..> StringLoader : 创建
    HttpFactory ..> HttpGlideUrlLoader : 创建
    ModelLoader <|.. StringLoader
    ModelLoader <|.. HttpGlideUrlLoader
    MultiModelLoaderFactory ..> ModelLoaderFactory : 调用注册项的 build
    MultiModelLoaderFactory ..> MultiModelLoader : 多个匹配项时创建
    ModelLoader <|.. MultiModelLoader

ModelLoaderFactory.build() 是一个由具体工厂实现的多态创建方法,因此可以用工厂方法模式理解。它没有《Head First》PizzaStore 示例中那样的订购业务模板,而是把创建协议放在专门的工厂接口里。这里的产品属于同一类抽象——ModelLoader;不能因为有多个 Factory,就称为创建多个相关产品族的抽象工厂。

MultiModelLoaderFactory.build(modelClass, dataClass) 会查找匹配注册项并调用各自工厂:一个匹配项直接返回加载器,多个匹配项组合为 MultiModelLoader。它还记录正在使用的注册项以避免递归构建循环;没有可用项时通常抛出异常,因递归保护而跳过的情况有空加载器分支。

多加载器的处理也分两个阶段:先通过 handles() 和 buildLoadData() 收集可用 Fetcher,再由 MultiFetcher 依次尝试读取。得到非空数据后返回成功;读取失败或返回 null 时尝试下一个,直到成功或全部失败。buildLoadData() 只是建立加载描述,实际 I/O 发生在 Fetcher 加载阶段。

源码:ModelLoaderFactory、StringLoader.StreamFactory、HttpGlideUrlLoader.Factory、MultiModelLoaderFactory、多加载器与读取回退。

策略:磁盘缓存决策

同一条解码流程可以采用不同缓存规则。DiskCacheStrategy 把“读哪一层磁盘缓存、是否写入原始数据或处理后的资源”封装成可以替换的策略对象。

角色 实际类型 职责
策略抽象 DiskCacheStrategy 定义四个读写决策方法
具体策略 ALL、NONE、DATA、RESOURCE、AUTOMATIC 使用匿名子类实现不同规则
使用策略的上下文 DecodeJob 选择缓存读取阶段,判断资源是否需要写入
数据读取侧 SourceGenerator、DecodeHelper 读取策略并决定是否缓存源数据
classDiagram
    class DiskCacheStrategy {
        <<abstract>>
        +isDataCacheable(dataSource) boolean
        +isResourceCacheable(alternateKey, dataSource, encodeStrategy) boolean
        +decodeCachedResource() boolean
        +decodeCachedData() boolean
    }
    class DataPolicy["DATA 的匿名实现"]
    class ResourcePolicy["RESOURCE 的匿名实现"]
    class AutomaticPolicy["AUTOMATIC 的匿名实现"]
    DiskCacheStrategy <|-- DataPolicy
    DiskCacheStrategy <|-- ResourcePolicy
    DiskCacheStrategy <|-- AutomaticPolicy
    DecodeJob --> DiskCacheStrategy : diskCacheStrategy
    SourceGenerator --> DecodeHelper : helper
    DecodeHelper --> DiskCacheStrategy : diskCacheStrategy

图中的三个实现节点用于展示匿名子类,源码没有名为 DataPolicy 等的顶层类;另外两种策略省略于图中。调用者通过 diskCacheStrategy(...) 选择策略,默认值为 AUTOMATIC。

策略 读取磁盘缓存 写入规则概要
NONE 两层都不读 两层都不写
DATA 原始数据层 写原始数据,但来源为数据磁盘缓存或内存缓存时不重复写
RESOURCE 处理后资源层 写处理后的资源,但来源为资源磁盘缓存或内存缓存时不重复写
ALL 两层都读 仅远程源数据写入数据层;资源层排除资源磁盘缓存、内存缓存来源
AUTOMATIC 两层都读 远程源数据写入数据层;本地来源或命中备用键的数据磁盘缓存,且编码策略为 TRANSFORMED 时,允许写资源层

这些方法给出的是缓存决策,真正写入还依赖编码器等运行条件。DiskCacheStrategy.NONE 仅关闭这里的磁盘缓存路径;内存缓存由其他选项控制,例如 skipMemoryCache(true),不能把两者混为一谈。

源码:DiskCacheStrategy 全部实现、BaseRequestOptions、DecodeJob 的阶段选择、资源写入决策、SourceGenerator。

观察者:生命周期驱动请求管理

Activity、Fragment 的启停不应该与每一个图片请求直接耦合。ActivityFragmentLifecycle 广播生命周期变化,RequestManager 作为观察者接收事件,再管理自己跟踪的请求。

角色 实际类型 职责
被观察者接口 Lifecycle 注册、移除监听器
具体被观察者 ActivityFragmentLifecycle 维护监听集合与当前状态,分发生命周期事件
观察者接口 LifecycleListener 定义 onStart/onStop/onDestroy
具体观察者 RequestManager 把生命周期事件转为请求管理操作
请求跟踪器 RequestTracker 启动、暂停、恢复和清理请求;不实现 LifecycleListener
classDiagram
    class Lifecycle {
        <<interface>>
        +addListener(listener)
        +removeListener(listener)
    }
    class LifecycleListener {
        <<interface>>
        +onStart()
        +onStop()
        +onDestroy()
    }
    Lifecycle <|.. ActivityFragmentLifecycle
    LifecycleListener <|.. RequestManager
    ActivityFragmentLifecycle --> "0..*" LifecycleListener : lifecycleListeners 弱引用
    RequestManager --> Lifecycle : lifecycle
    RequestManager --> RequestTracker : requestTracker
    RequestTracker --> "0..*" Request : 跟踪请求

RequestManager 注册自身后,onStart() 恢复请求,onStop() 暂停运行中的请求,onDestroy() 清理请求并移除监听。恢复操作会重新启动尚未成功且当前未运行的已跟踪请求,因此也可能重试失败请求。

这个实现的两个细节很重要:

  • 注册时立即同步状态:ActivityFragmentLifecycle.addListener() 加入集合后立即调用一次 onDestroy()、onStart() 或 onStop()。新建且尚未启动的生命周期会立即回调 onStop(),无需等待下一次事件。
  • 弱引用有明确范围:生命周期监听集合由 WeakHashMap 支撑,RequestTracker.requests 也使用弱引用,但暂停时暂存的 pendingRequests 使用强引用。不能由此推断整个请求树都由弱引用持有。

这种设计让生命周期对象只依赖监听接口;请求的实际暂停、恢复逻辑可以独立维护。它属于观察者关系,不要求观察者和被观察者继承同一个类。

源码:Lifecycle、LifecycleListener、ActivityFragmentLifecycle、RequestManager 的注册、生命周期响应、RequestTracker。

组合:缩略图与错误请求组成请求树

单次图片加载可能同时包含主图、缩略图和失败备用图。调用方仍然只需要对根节点执行 begin()、pause()、clear(),不必逐个操作内部请求。这就是组合模式在这里的价值。

角色 实际类型 职责
统一组件 Request 定义请求操作和状态查询
叶子 SingleRequest 执行一次具体资源加载并向父协调器报告
组合节点 ThumbnailRequestCoordinator 管理 full 和 thumb 两个子请求
组合节点 ErrorRequestCoordinator 管理 primary 和 error 两个子请求
协调协议 RequestCoordinator 判断显示权限,接收子请求成功/失败通知
classDiagram
    class Request {
        <<interface>>
        +begin()
        +pause()
        +clear()
    }
    class RequestCoordinator {
        <<interface>>
        +canSetImage(request) boolean
        +onRequestSuccess(request)
        +onRequestFailed(request)
    }
    class Thumbnail["ThumbnailRequestCoordinator"]
    class Error["ErrorRequestCoordinator"]
    Request <|.. SingleRequest
    Request <|.. Thumbnail
    Request <|.. Error
    RequestCoordinator <|.. Thumbnail
    RequestCoordinator <|.. Error
    Thumbnail --> "2" Request : full / thumb
    Error --> "2" Request : primary / error
    SingleRequest --> "0..1" RequestCoordinator : requestCoordinator
    Thumbnail --> "0..1" RequestCoordinator : parent
    Error --> "0..1" RequestCoordinator : parent

RequestCoordinator 和 Request 是两个独立接口,前者不继承后者;两个具体协调器同时实现它们。子节点类型为 Request,所以还可以是另一棵请求树。它没有通用的 addChild(),每个协调器通过 setRequests() 配置两个具有明确职责的子请求。

当同一个 Builder 同时设置 thumbnail 和 error 时,典型结构为:

1
2
3
4
5
ErrorRequestCoordinator
├── primary → ThumbnailRequestCoordinator
│             ├── full  → SingleRequest
│             └── thumb → Request(也可以继续嵌套)
└── error   → Request(也可以继续嵌套)

RequestBuilder 递归构建这棵树,整树共享 Target 和请求锁;交给 Target 与跟踪器的是根 Request。没有这些配置时,根节点可以直接是 SingleRequest。

协作过程 缩略图协调器 错误协调器
启动 通常先启动 thumb,再启动 full,不等待 thumb 完成 先启动 primary,primary 失败后才启动 error
成功/失败上报 以 full 的结果向父节点报告,thumb 的结果只更新本分支状态 任一分支成功可上报成功;primary 失败先启动 error,error 也失败才上报失败
清理 clear() 清理两个子请求 clear() 清理 primary,并按状态清理 error

因此,“缩略图已经成功”不等于整组成功:full 失败仍可以触发外层 error。full 成功时也不是无条件清理 thumb,而是仅清理尚未处于成功/失败终态的 thumb。子节点能否更新 Target,还要经过协调器的权限判断;启动 error 本身不代表自动取消 primary 子树里所有仍在运行的请求。

源码:Request、RequestCoordinator、ThumbnailRequestCoordinator、ErrorRequestCoordinator、SingleRequest 的协调回调、RequestBuilder 的树构建。

模板方法:统一 Bitmap 转换流程

居中裁剪和完整适配等算法都需要处理输入尺寸、取得位图池、读取原资源和包装输出。BitmapTransformation 固定这些步骤,将真正的像素变换留给子类。

角色 实际类型或方法 职责
转换接口 Transformation<Bitmap> 约定资源转换能力
模板类 BitmapTransformation 实现不可被覆盖的公有转换入口
模板方法 final transform(Context, Resource<Bitmap>, int, int) 校验尺寸、取池、调用钩子、包装结果
算法钩子 protected abstract transform(BitmapPool, Bitmap, int, int) 返回变换后的 Bitmap
具体子类 CenterCrop、FitCenter 分别执行等比缩放后裁剪、等比缩放适配
classDiagram
    class Transformation {
        <<interface>>
        +transform(context, resource, width, height) Resource
    }
    class BitmapTransformation {
        <<abstract>>
        +transform(context, resource, width, height) Resource
        #transform(pool, bitmap, width, height) Bitmap*
    }
    Transformation <|.. BitmapTransformation
    BitmapTransformation <|-- CenterCrop
    BitmapTransformation <|-- FitCenter
    BitmapTransformation ..> BitmapPool : 从 Glide 获取
    BitmapTransformation ..> BitmapResource : 包装新结果

两个 transform 是不同参数的重载。公有入口带有 final,子类覆盖的是受保护的算法钩子。模板依次校验尺寸、取得 BitmapPool、读取原图,将 SIZE_ORIGINAL 换成对应的原始宽高,然后调用钩子。若结果与原 Bitmap 相同,复用原 Resource;否则通过 BitmapResource.obtain() 包装新结果。

位图池在这里是局部取得的依赖,模板类没有持有它的实例字段。钩子不得自行回收输入位图或最终返回的位图;转换替换资源时,旧资源的回收由外层 DecodeJob 处理。CenterCrop 和 FitCenter 复用模板流程,并分别委托 TransformationUtils 中的算法。

源码:BitmapTransformation、CenterCrop、FitCenter、TransformationUtils、DecodeJob 回收旧资源。

装饰者:为 Resource 增加引用计数

一个资源可能被多个请求使用。原始资源只需要知道如何访问数据和回收自身;EngineResource 在同一个 Resource 接口外包上一层,增加使用计数、缓存属性和回收检查。

角色 实际类型 职责
组件接口 Resource<Z> 提供数据、类型、大小以及回收操作
具体组件示例 BitmapResource 包装 Bitmap,回收时将它交给 BitmapPool
装饰者 EngineResource<Z> 委托数据访问,增加 acquire/release 和回收控制
释放监听器 EngineResource.ResourceListener 接收计数归零通知
实际监听与调度 Engine 决定资源进入内存缓存还是回收流程
classDiagram
    class Resource {
        <<interface>>
        +get()
        +getSize() int
        +recycle()
    }
    class EngineResource {
        -int acquired
        -boolean isMemoryCacheable
        -boolean isRecyclable
        ~acquire()
        ~release()
        +recycle()
    }
    class ResourceListener["EngineResource.ResourceListener"] {
        <<interface>>
        +onResourceReleased(key, resource)
    }
    Resource <|.. EngineResource
    Resource <|.. BitmapResource
    EngineResource --> Resource : resource
    EngineResource --> ResourceListener : listener
    ResourceListener <|.. Engine
    BitmapResource --> BitmapPool : bitmapPool
    BitmapResource --> Bitmap : bitmap

get()、getResourceClass()、getSize() 委托给被包装资源。acquire() 增加计数;release() 减少计数,降为零时通知监听器。这里记录的是 Glide 显式管理的使用次数,不是 JVM 自动统计的引用数量,调用 get() 也不会自动增加计数。

释放和回收是两个步骤:计数归零后,Engine.onResourceReleased() 移除活跃记录;允许内存缓存的资源进入缓存,否则交给 ResourceRecycler。只有真正执行 EngineResource.recycle() 时,才检查是否仍有人使用、是否已经回收,并在 isRecyclable 为 true 时继续回收内部资源。

isMemoryCacheable 控制是否可进入内存缓存,isRecyclable 控制是否向内部资源传播回收,两者不是同一个开关。外层包装器即使不传播回收,也会标记自身已回收。

BitmapResource.recycle() 调用 BitmapPool.put(bitmap),不等于立即销毁位图。内存缓存复用的是按 Key 查找的加载结果,位图池复用的是用于后续解码/变换的位图内存。池可能保存位图,也可能拒收并销毁;归还后调用方不能继续使用它。BitmapResource.obtain() 创建包装对象,并不是从位图池取出一个包装器。

源码:Resource、EngineResource、Engine 的释放与回收、ResourceRecycler、BitmapResource、BitmapPool。

适配器:把 String 输入转为 Uri 加载

调用方可以传入字符串路径或 URL,但底层已经有基于 Uri 的加载器。StringLoader 负责转换输入并委托处理,因此不需要再实现一遍本地文件、ContentResolver 或网络读取逻辑。

角色 实际类型 职责
面向调用方的目标接口 ModelLoader<String, Data> 接收字符串模型
适配器 StringLoader<Data> 将 String 转为 Uri,委托 uriLoader
被适配的能力 ModelLoader<Uri, Data> 处理已经解析的 Uri,可由多个加载器组合提供
本地 Uri 加载实现 UriLoader<Data> 支持 file、android.resource、content
网络 Uri 适配实现 UrlUriLoader<Data> 将 http/https Uri 转为 GlideUrl,再委托网络加载器
classDiagram
    class StringContract["ModelLoader (String, Data)"] {
        <<interface>>
        +buildLoadData(model, width, height, options) LoadData
    }
    class UriContract["ModelLoader (Uri, Data)"] {
        <<interface>>
        +handles(uri) boolean
        +buildLoadData(uri, width, height, options) LoadData
    }
    StringContract <|.. StringLoader
    StringLoader --> UriContract : uriLoader
    UriContract <|.. UriLoader
    UriContract <|.. UrlUriLoader
    UriContract <|.. MultiModelLoader
    UrlUriLoader ..> GlideUrl : 转换输入
    UrlUriLoader --> ModelLoader : urlLoader 使用 GlideUrl

图中带括号的节点表示同一个 ModelLoader 泛型接口在不同模型类型上的使用,不是源码中的两个独立接口;MultiModelLoader 也只画出被用于 Uri 的这一种情况。

StringLoader.buildLoadData() 先转换模型:空字符串得到 null;以 / 开头的路径或没有 scheme 的字符串被转成文件 Uri;其余按 Uri 解析。无法转换或委托加载器无法处理时返回 null,否则继续委托。StringLoader.handles() 刻意返回 true,避免重复解析,因此它并不保证每个字符串都最终能得到可用加载数据。

网络地址的一条典型适配路径是:String → Uri → GlideUrl → HttpUrlFetcher。在这个版本中,处理 http/https Uri 的注册实现是 UrlUriLoader;UriLoader 负责前述本地 scheme,不能把所有 Uri 读取都归给它。中间还可能经过 MultiModelLoader 选择和组合可处理的加载器。

这里与装饰者的区别可以从意图和接口看出来:EngineResource 保持相同资源契约并增加管理行为;StringLoader 则把面向 String 的调用转换为面向 Uri 的调用,以复用另一种输入模型的能力。两者都使用委托,但解决的问题不同。

源码:StringLoader、UriLoader、UrlUriLoader、HttpGlideUrlLoader、默认组件注册。

参考

评论