Glide 整体架构之美赏析

Glide是一个高效、灵活的Android图片加载库,其架构设计精巧,层次分明。本文将对Glide的整体架构进行详细分析。

1. 总体架构概览

Glide采用了模块化设计,核心组件通过注册表(Registry)进行管理,使用流畅的链式API创建请求,并由Engine引擎处理资源加载和缓存管理。整个框架遵循单例模式、构建者模式和工厂模式等设计模式。

复制代码
Glide  
   ├── RequestManager - 管理生命周期和请求  
   ├── Registry - 组件注册管理  
   ├── Engine - 加载和缓存处理引擎  
   ├── DecodeJob - 解码工作  
   └── BitmapPool/MemoryCache - 资源管理  

2. 核心组件解析

2.1 Glide单例

Glide通过静态单例模式提供整个应用程序的一致入口点:

less 复制代码
public static Glide get(@NonNull Context context) {  
  if (glide == null) {  
    GeneratedAppGlideModule annotationGeneratedModule =  
        getAnnotationGeneratedGlideModules(context.getApplicationContext());  
    synchronized (Glide.class) {  
      if (glide == null) {  
        checkAndInitializeGlide(context, annotationGeneratedModule);  
      }  
    }  
  }  
  return glide;  
}

Glide类负责创建和管理所有主要组件,包括BitmapPool、MemoryCache、Registry等:

less 复制代码
Glide(  
    @NonNull Context context,  
    @NonNull Engine engine,  
    @NonNull MemoryCache memoryCache,  
    @NonNull BitmapPool bitmapPool,  
    @NonNull ArrayPool arrayPool,  
    @NonNull RequestManagerRetriever requestManagerRetriever,  
    @NonNull ConnectivityMonitorFactory connectivityMonitorFactory,  
    int logLevel,  
    @NonNull RequestOptionsFactory defaultRequestOptionsFactory,  
    @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,  
    @NonNull List<RequestListener<Object>> defaultRequestListeners,  
    @NonNull List<GlideModule> manifestModules,  
    @Nullable AppGlideModule annotationGeneratedModule,  
    @NonNull GlideExperiments experiments) {  
  this.engine = engine;  
  this.bitmapPool = bitmapPool;  
  this.arrayPool = arrayPool;  
  this.memoryCache = memoryCache;  
  this.requestManagerRetriever = requestManagerRetriever;  
  this.connectivityMonitorFactory = connectivityMonitorFactory;  
  this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;

2.2 组件注册系统

Glide使用Registry来管理所有可扩展组件,包括解码器、转换器等。RegistryFactory负责创建和初始化Registry:

java 复制代码
static GlideSupplier<Registry> lazilyCreateAndInitializeRegistry(  
    final Glide glide,  
    final List<GlideModule> manifestModules,  
    @Nullable final AppGlideModule annotationGeneratedModule) {  
  return new GlideSupplier<Registry>() {  
    // Rely on callers using memoization if they want to avoid duplicate work, but  
    // rely on ourselves to verify that no recursive initialization occurs.  
    private boolean isInitializing;  
  
    @Override  
    public Registry get() {  
      if (isInitializing) {  
        throw new IllegalStateException(  
            "Recursive Registry initialization! In your"  
                + " AppGlideModule and LibraryGlideModules, Make sure you're using the provided "  
                + "Registry rather calling glide.getRegistry()!");  
      }  
      Trace.beginSection("Glide registry");  
      isInitializing = true;  
      try {  
        return createAndInitRegistry(glide, manifestModules, annotationGeneratedModule);  
      } finally {  
        isInitializing = false;  
        Trace.endSection();  
      }  
    }  
  };  
}

Registry负责将不同的模型类型、数据类型、资源类型和转码类型连接起来,形成一个完整的加载管道:

typescript 复制代码
private static void initializeDefaults(  
    Context context,  
    Registry registry,  
    BitmapPool bitmapPool,  
    ArrayPool arrayPool,  
    GlideExperiments experiments) {  
  registry.register(new DefaultImageHeaderParser());  
  // Right now we're only using this parser for HEIF images, which are only supported on OMR1+.  
  // If we need this for other file types, we should consider removing this restriction.  
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {  
    registry.register(new ExifInterfaceImageHeaderParser());  
  }

2.3 请求构建系统

RequestBuilder采用流畅的API设计,允许开发者链式设置各种选项:

scala 复制代码
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>  
    implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {  
  // Used in generated subclasses  
  protected static final RequestOptions DOWNLOAD_ONLY_OPTIONS =  
      new RequestOptions()  
          .diskCacheStrategy(DiskCacheStrategy.DATA)  
          .priority(Priority.LOW)  
          .skipMemoryCache(true);  
  
  private final Context context;  
  private final RequestManager requestManager;  
  private final Class<TranscodeType> transcodeClass;  
  private final Glide glide;  
  private final GlideContext glideContext;

2.4 解码与转换系统

Glide的解码工作由DecodeJob完成,它负责协调数据获取、缓存检查和资源解码:

java 复制代码
class DecodeJob<R>  
    implements DataFetcherGenerator.FetcherReadyCallback,  
        Runnable,  
        Comparable<DecodeJob<?>>,  
        Poolable {  
  private static final String TAG = "DecodeJob";  
  
  private final DecodeHelper<R> decodeHelper = new DecodeHelper<>();  
  private final List<Throwable> throwables = new ArrayList<>();  
  private final StateVerifier stateVerifier = StateVerifier.newInstance();  
  private final DiskCacheProvider diskCacheProvider;  
  private final Pools.Pool<DecodeJob<?>> pool;  
  private final DeferredEncodeManager<?> deferredEncodeManager = new DeferredEncodeManager<>();  
  private final ReleaseManager releaseManager = new ReleaseManager();

DecodeJob使用状态机模式,在不同阶段间转换:

csharp 复制代码
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);  
  }  
}

2.5 图像转换系统

Glide提供了丰富的内置图像转换功能,如剪裁、缩放和圆角处理:

arduino 复制代码
public static Bitmap centerCrop(  
    @NonNull BitmapPool pool, @NonNull Bitmap inBitmap, int width, int height) {  
  if (inBitmap.getWidth() == width && inBitmap.getHeight() == height) {  
    return inBitmap;  
  }  
  // From ImageView/Bitmap.createScaledBitmap.  
  final float scale;  
  final float dx;  
  final float dy;  
  Matrix m = new Matrix();  
  if (inBitmap.getWidth() * height > width * inBitmap.getHeight()) {  
    scale = (float) height / (float) inBitmap.getHeight();  
    dx = (width - inBitmap.getWidth() * scale) * 0.5f;  
    dy = 0;  
  } else {  
    scale = (float) width / (float) inBitmap.getWidth();  
    dx = 0;  
    dy = (height - inBitmap.getHeight() * scale) * 0.5f;  
  }

自定义转换则通过实现BitmapTransformation接口:

ruby 复制代码
/**  
 * A simple {@link com.bumptech.glide.load.Transformation} for transforming {@link  
 * android.graphics.Bitmap}s that abstracts away dealing with {@link  
 * com.bumptech.glide.load.engine.Resource} objects for subclasses.  
 *  
 * <p>Use cases will look something like this:  
 *  
 * <pre>{@code  
 * public class FillSpace extends BitmapTransformation {  
 *     private static final String ID = "com.bumptech.glide.transformations.FillSpace";  
 *     private static final byte[] ID_BYTES = ID.getBytes(Charset.forName("UTF-8"));  
 *  
 *     {@literal @Override}  
 *     public Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {  
 *         if (toTransform.getWidth() == outWidth && toTransform.getHeight() == outHeight) {  
 *             return toTransform;  
 *         }  
 *  
 *         return Bitmap.createScaledBitmap(toTransform, outWidth, outHeight, true);  
 *     }

3. 资源管理

Glide对内存和磁盘资源进行精细管理,包括内存缓存、磁盘缓存和位图池:

scss 复制代码
public void trimMemory(int level) {  
  // Engine asserts this anyway when removing resources, fail faster and consistently  
  Util.assertMainThread();  
  // Request managers need to be trimmed before the caches and pools, in order for the latter to  
  // have the most benefit.  
  synchronized (managers) {  
    for (RequestManager manager : managers) {  
      manager.onTrimMemory(level);  
    }  
  }  
  // memory cache needs to be trimmed before bitmap pool to trim re-pooled Bitmaps too. See #687.  
  memoryCache.trimMemory(level);  
  bitmapPool.trimMemory(level);  
  arrayPool.trimMemory(level);  
}

4. 流式请求API

Glide提供了简洁直观的API,使用链式调用构建图片加载请求:

typescript 复制代码
public static RequestManager with(@NonNull Context context) {  
  return getRetriever(context).get(context);  
}  
  
/**  
 * Begin a load with Glide that will be tied to the given {@link android.app.Activity}'s lifecycle  
 * and that uses the given {@link Activity}'s default options.  
 *  
 * @param activity The activity to use.  
 * @return A RequestManager for the given activity that can be used to start a load.  
 * @deprecated This is equivalent to calling {@link #with(Context)} using the application context.  
 *     Use the androidx Activity class instead (ie {@link FragmentActivity}, or {@link  
 *     androidx.appcompat.app.AppCompatActivity}).  
 */

总结

Glide的架构设计体现了几个核心原则:

  1. 模块化:各组件分工明确,易于扩展和定制
  2. 资源优化:通过精细的内存管理和缓存机制提高性能
  3. API友好:流畅的链式API设计使用简单直观
  4. 生命周期感知:与Android组件生命周期集成,避免内存泄漏
  5. 可扩展性:通过Registry系统支持自定义组件注册

这种优雅的架构设计使Glide能够高效处理图片加载、转换和缓存,同时保持API的简洁性和可扩展性,堪称Android图片加载库架构设计的典范。

Notes

本文分析基于Glide源码,着重解析了Glide的核心架构组件和设计模式。还有更多细节如线程池管理、优先级处理等未能完全展开,有兴趣的读者可以进一步深入研究源码。

相关推荐
六边形6662 分钟前
Vue中的 ref、toRef 和 toRefs 有什么区别
前端·vue.js·面试
前端付豪3 分钟前
🚀 React 应用国际化实战:深入掌握 react-i18next 的高级用法
前端·react.js·架构
brzhang23 分钟前
代码Review老被怼?这10个编程好习惯,让你写出同事都点赞的好代码!
前端·后端·架构
brzhang43 分钟前
告别 CURD,走向架构:一份帮你打通任督二脉的知识地图
前端·后端·架构
brzhang1 小时前
代码越写越乱?掌握这 5 种架构模式,小白也能搭出清晰系统!
前端·后端·架构
bxlj_jcj1 小时前
如何实现Redis和Mysql中数据双写一致性
redis·缓存·架构
brzhang1 小时前
告别『上线裸奔』!一文带你配齐生产级 Web 应用的 10 大核心组件
前端·后端·架构
shepherd1111 小时前
Kafka生产环境实战经验深度总结,让你少走弯路
后端·面试·kafka
南客先生1 小时前
多级缓存架构设计与实践经验
java·面试·多级缓存·缓存架构
zayyo1 小时前
Vue.js性能优化新思路:轻量级SSR方案深度解析
前端·面试·性能优化