Glide配置:AppGlideModule

QuibblerQuibbler 2020-11-21 约 20 分钟 4052 次阅读

Glide配置:AppGlideModule

Glide用起来非常方便,基本用法见Glide的基本用法,简短的一句链式调用就能给ImageView设置图片。而且自带缓存实现,如果不进行额外的设置Glide的缓存目录、缓存大小都是默认的。应用可以自行进行定制修改,就用到AppGlideModule。

1、自定义AppGlideModule

配置Glide加载图片的设置、缓存设置、缓存策略,就需要应用自己继承AppGlideModule类,实现里面的空方法:

public class ApplicationGlideModule extends AppGlideModule {
        @Override
        public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
            super.applyOptions(context, builder);
        }
        @Override
        public boolean isManifestParsingEnabled() {
            return super.isManifestParsingEnabled();
        }
    }

2、GlideBuilder

applyOptions(Context context,GlideBuilder builder)方法就是我们需要关注的,传入的GlideBuilder类型参数,典型的创建者模式,用来创建Glide实例(Glide是单例的)。其中有非常多的配置项:

/** A builder class for setting default structural classes for Glide to use. */
  @SuppressWarnings("PMD.ImmutableField")
  public final class GlideBuilder {
    private final Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions = new ArrayMap<>();
    private Engine engine;
    private BitmapPool bitmapPool;
    private ArrayPool arrayPool;
    private MemoryCache memoryCache;
    private GlideExecutor sourceExecutor;
    private GlideExecutor diskCacheExecutor;
    private DiskCache.Factory diskCacheFactory;
    private MemorySizeCalculator memorySizeCalculator;
    private ConnectivityMonitorFactory connectivityMonitorFactory;
    ...
  }

如果应用不进行设置,Glide会全部使用默认配置去创建Glide实例:

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(),
              animationExecutor,
              isActiveResourceRetentionAllowed);
    }
    if (defaultRequestListeners == null) {
      defaultRequestListeners = Collections.emptyList();
    } else {
      defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
    }
    RequestManagerRetriever requestManagerRetriever =
        new RequestManagerRetriever(requestManagerFactory);
    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptionsFactory,
        defaultTransitionOptions,
        defaultRequestListeners,
        isLoggingRequestOriginsEnabled,
        isImageDecoderEnabledForBitmaps);
  }

2.1、设置Bitmap缓冲池

①setBitmapPool(BitmapPool bitmapPool):Bitmap对象复用缓冲池

//设置Bitmap缓冲池大小32Mb
    builder.setBitmapPool(new LruBitmapPool(1024 * 1024 * 32));

开发者可以实现BitmapPool接口,实现自己的Bitmap缓冲池。默认的LruBitmapPool实现已经非常优秀!

/** An interface for a pool that allows users to reuse {@link android.graphics.Bitmap} objects. */
public interface BitmapPool {
  ...
}

2.2、设置内存缓存

①setMemoryCache(MemoryCache memoryCache):设置内存缓存

builder.setMemoryCache(new LruResourceCache(32 * 1024 * 1024));

同样可以实现MemoryCache接口,自定义内存缓存。不过Glide自带的LruResourceCache已经足够优秀。

/** An interface for adding and removing resources from an in memory cache. */
  public interface MemoryCache {
    ...
  }

2.3、配置磁盘缓存

①setDiskCache(DiskCache.Factory diskCacheFactory)

builder.setDiskCache(new DiskLruCacheFactory("image", 32 * 1024 * 1024));

DiskCache.Factory接口定义如下,Glide磁盘缓存默认存储在私有data/data/包名/cache/image_manager_disk_cache目录下,250Mb的缓存。

/** An interface for lazily creating a disk cache. */
  interface Factory {
    /** 250 MB of cache. */
    int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024;
    String DEFAULT_DISK_CACHE_DIR = "image_manager_disk_cache";
    ...
  }

有几个默认的实现,一个是内部存储缓存InternalCacheDiskCacheFactory

//设置128Mb的磁盘缓存大小,目录名仍使用默认的
    builder.setDiskCache(new InternalCacheDiskCacheFactory(context, 128 * 1024 * 1024));

另一个是外部磁盘缓存ExternalCacheDiskCacheFactory。不过已经废弃,从Android 11开始建议使用私有目录。

builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, 128 * 1024 * 1024));

2.4、配置图片加载选项

①setDefaultRequestOptions(final RequestOptions requestOptions)

RoundedCorners roundedCorners = new RoundedCorners(6);
    RequestOptions requestOptions = RequestOptions.bitmapTransform(roundedCorners);

构造一个RequestOptions对象,进行各种设置,加载图片的时候使用这个默认的。不用每次使用Glide加载图片开始with()...的时候单独再设置。

builder.setDefaultRequestOptions(requestOptions
            .format(DecodeFormat.PREFER_ARGB_8888)
            .diskCacheStrategyOf(DiskCacheStrategy.RESOURCE)
            .skipMemoryCache(false)
            .encodeQuality(50));

2.5、线程执行器

应用线程过多在性能和耗电上是一个大问题。曾在知乎上看到一篇文章支付宝峰值线程数量高达300多条。Glide内部有自己的线程池实现,如果不设置线程池,Glide会创建自己的线程执行器。

当然最好可以使用应用公用的线程池:

①setDiskCacheExecutor(GlideExecutor service)

②setSourceExecutor(GlideExecutor service)

③setAnimationExecutor(GlideExecutor service)

3、组件注册

自定义好应用的组件如何注册给Glide使之生效呢?

3.1、AndroidManifest中注册

在androidmanifest.xml中的<application />节点下添加<meta-data />,关于Meta Data详见Android meta-data用法。

<application>
    
        <meta-data
            android:name="com.quibbler.news.ApplicationGlideModule"
            android:value="AppGlideModule" />
            
    </application>

Glide在创建的时候会去加载AndroidManifest中的配置(以后有空分析一下这里解析的原理),isManifestParsingEnabled()方法的默认实现就是true

/**
   * Returns {@code true} if Glide should check the AndroidManifest for {@link GlideModule}s.
   *
   * <p>Implementations should return {@code false} after they and their dependencies have migrated
   * to Glide's annotation processor.
   *
   * <p>Returns {@code true} by default.
   */
  public boolean isManifestParsingEnabled() {
    return true;
  }

3.2、@GlideModule注解

在自定义的AppGlideModule类上加上@GlideModule注解

import com.bumptech.glide.annotation.GlideModule;
    
    @GlideModule
    public class ApplicationGlideModule extends AppGlideModule {
        ...
    }

不过别忘了,需要在build.gradle中添加Glide专门的annotationProcessor注解处理器

//Glide
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

同时需要重写isManifestParsingEnabled()方法,返回false,不需要解析AndroidManifest中的配置,有利于提高Glide初始化速度

@Override
    public boolean isManifestParsingEnabled() {
        return false;
    }

4、注意

①自定义的AppGlideModule需要在app/proguard-rules.pro混淆配置文件中配置避免被混淆,以免Glide加载模块出现问题。

-keep public class * implements com.bumptech.glide.module.GlideModule
-keep class * extends com.bumptech.glide.module.AppGlideModule {
 <init>(...);
}

②APP应用只能定义一个AppGlideModule模块,超过一个会在编译时报错。aar库应用不能实现AppGlideModule,需要使用LibraryGlideModules。

参考资料:

        最全Glide 配置、缓存

        Glide配置和自定义模块

        最简Glide4.8.0配置

        Glide缓存配置

        Glide中的缓存

        Android-Glide配置介绍

        

相关推荐

Airbnb开源项目
精选开源

Airbnb开源项目

Airbnb Engineering & Data ScienceAirflow Use Apache Airflow (incubating) to author workflows as directed acyclic graphs (DAGs) of tasks12,263Airpal Web UI for PrestoDB2,502Aerosolve A machine learning

2.3k
WilliamChart:轻量美观的 Android 图表库实战
精选开源

WilliamChart:轻量美观的 Android 图表库实战

WilliamChart:轻量美观的 Android 图表库实战数据可视化是运动、健康、金融、统计类 App 的刚需。MPAndroidChart 功能最全但偏重复杂,WilliamChart 走的则是"轻量 + 美观 + Kotlin 原生"路线——v3 用 Kotlin 完全重写,API 极简,一行 chart.animate(dataSet) 就能把数据画成带动画的折线/柱状/环形图,开箱即

175
sherpa解析:开源语音技术全家桶
精选开源

sherpa解析:开源语音技术全家桶

想在手机、树莓派甚至 RISC-V 开发板上离线跑语音识别,五年前还是个需要啃 Kaldi 源码的硬核课题。k2-fsa 组织的 sherpa 把这件事变成了"下载预训练模型、装个包、跑示例"的三步操作。这个以 Apache-2.0 协议开源的项目自我定位是"新一代 Kaldi 的语音转文本框架",它专注端到端模型的推理部署:transducer 与 CTC 两类架构,C++ 与 Python 双…

44