美文网首页
图片框架 - Glide自定义配置和组件及Registry机制

图片框架 - Glide自定义配置和组件及Registry机制

作者: Stan_Z | 来源:发表于2020-07-17 12:45 被阅读0次

    接上篇,代码依然是4.11.0版本。

    一、自定义配置和组件

    1.1 Glide如何实现自定义配置和组件
    /**
     * GlideModule注册方式:
     * 1)在application中加入:
     *  <meta-data
     *      android:name="xxx.xxx.xxx.glide.configure.CustomGlideMoudle"
     *      android:value="GlideModule" />
     * 2)@GlideModule注解
     */
    @GlideModule
    public final class CustomAppGlideModule extends AppGlideModule {
    
      //自定义配置
       @Override
       public void applyOptions(Context context, GlideBuilder builder) {
       这里主要配置GlideBuilder
          常用设置项:
          setMemoryCache() //用于配置Glide的内存缓存策略,默认配置是LruResourceCache。
          setBitmapPool()//用于配置Glide的Bitmap缓存池,默认配置是LruBitmapPool。
          setDiskCache()//用于配置Glide的硬盘缓存策略,默认配置是InternalCacheDiskCacheFactory。
          setDiskCacheService()//用于配置Glide读取缓存中图片的异步执行器,默认配置是FifoPriorityThreadPoolExecutor,也就是先入先出原则。
          setResizeService()//用于配置Glide读取非缓存中图片的异步执行器,默认配置也是FifoPriorityThreadPoolExecutor。
          setDecodeFormat()//用于配置Glide加载图片的解码模式,默认配置是RGB_565。
        }
    
    /**
    * Glide V4 版本,禁用清单解析选项
    */
    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    
    }
    
    //自定义组件
    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
    这里通过Registry对组件进行注册
    append 尾部追加
    prepend 头部插入
    register 注册、相当于append
    replace 替换掉相同条件的模块
         }
    }
    
    1.2 自定义配置和组件的调用流程

    Glide本身是单例,最初的初始化:

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

    看 getAnnotationGeneratedGlideModules(context.getApplicationContext()):

    private static GeneratedAppGlideModule getAnnotationGeneratedGlideModules(Context context) {
      GeneratedAppGlideModule result = null;
      try {
        Class<GeneratedAppGlideModule> clazz =
            (Class<GeneratedAppGlideModule>)
                Class.forName("com.bumptech.glide.GeneratedAppGlideModuleImpl");
       result = clazz.getDeclaredConstructor(Context.class).newInstance(context.getApplicationContext());
      } catch (ClassNotFoundException e) {
      ... 
     }
      return result;
    }
    

    它本身就是通过反射来使用com.bumptech.glide.GeneratedAppGlideModuleImpl 这个类。找下这个类:

    很明显是由APT生成的,既然是APT,那就去找对应生成文件的Porcessor

    对应的Glide引库为:annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

    com.bumptech.glide.GeneratedAppGlideModuleImpl生成的主Processor在:

    @AutoService(Processor.class)
    public final class GlideAnnotationProcessor extends AbstractProcessor {
      static final boolean DEBUG = false;
      private ProcessorUtil processorUtil;
      private LibraryModuleProcessor libraryModuleProcessor;
      private AppModuleProcessor appModuleProcessor;
      private boolean isGeneratedAppGlideModuleWritten;
      private ExtensionProcessor extensionProcessor;
    
      @Override
      public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
       processorUtil = new ProcessorUtil(processingEnvironment);
       IndexerGenerator indexerGenerator = new IndexerGenerator(processorUtil);
       libraryModuleProcessor = new LibraryModuleProcessor(processorUtil, indexerGenerator);
       appModuleProcessor = new AppModuleProcessor(processingEnvironment, processorUtil);
       extensionProcessor =
            new ExtensionProcessor(processingEnvironment, processorUtil, indexerGenerator);
      }
    
      @Override
      public Set<String> getSupportedAnnotationTypes() {
        Set<String> result = new HashSet<>();
       result.addAll(libraryModuleProcessor.getSupportedAnnotationTypes());
       result.addAll(extensionProcessor.getSupportedAnnotationTypes());
       return result;
      }
    
      @Override
      public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
      }
    
      @Override
      public boolean process(Set<? extends TypeElement> set, RoundEnvironment env) {
        processorUtil.process();
       boolean newModulesWritten = libraryModuleProcessor.processModules(env);
       boolean newExtensionWritten = extensionProcessor.processExtensions(env);
       appModuleProcessor.processModules(set, env);
       if (newExtensionWritten || newModulesWritten) {
          if (isGeneratedAppGlideModuleWritten) {
            throw new IllegalStateException("Cannot process annotations after writing AppGlideModule");
         }
          return true;
       }
    
        if (!isGeneratedAppGlideModuleWritten) {
          isGeneratedAppGlideModuleWritten = appModuleProcessor.maybeWriteAppModule();
       }
        return true;
      }
    }
    

    不了解编译时注解的可以参考之前的文章:Java基础(二)-注解

    运行时注解简而言之就是在编译器生成一个类文件,类的内容通过javapoet组装出来。这个不是本文的重点,点到为止,那么来看看

    生成后的内容:

    @SuppressWarnings("deprecation")
    final class GeneratedAppGlideModuleImpl extends GeneratedAppGlideModule {
      private final CustomAppGlideModule appGlideModule;
      GeneratedAppGlideModuleImpl() {
        //CustomAppGlideModule 实现了AppGlideModule,并且由@GlideModule方式注册
        appGlideModule = new CustomAppGlideModule();
       if (Log.isLoggable("Glide", Log.DEBUG)) {
          Log.d("Glide", "Discovered AppGlideModule from annotation: com.mgtv.lib.tv.imageloader.CustomAppGlideModule");
         Log.d("Glide", "Discovered LibraryGlideModule from annotation: com.bumptech.glide.integration.webp.WebpGlideLibraryModule");
       }
      }
    
      @Override
      public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        appGlideModule.applyOptions(context, builder);
      }
    
      @Override
      public void registerComponents(@NonNull Context context, @NonNull Glide glide,
         @NonNull Registry registry) {
        //WebpGlideLibraryModule 实现了LibraryGlideModule,并且由@GlideModule方式注册
        new WebpGlideLibraryModule().registerComponents(context, glide, registry);
       appGlideModule.registerComponents(context, glide, registry);
      }
    
      @Override
      public boolean isManifestParsingEnabled() {
        return appGlideModule.isManifestParsingEnabled();
      }
    
      @Override
      @NonNull
      public Set<Class<?>> getExcludedModuleClasses() {
        return Collections.emptySet();
      }
    
      @Override
      @NonNull
      GeneratedRequestManagerFactory getRequestManagerFactory() {
        return new GeneratedRequestManagerFactory();
      }
    }
    

    这里总结下本地的配置在GeneratedAppGlideModuleImpl生成的规则:

    • AppGlideModule 只能实现1个,但是LibraryGlideModule可以实现多个。LibraryGlideModule只有registerComponents自定义组件功能,而AppGlideModule在LibraryGlideModule基础上增加了applyOptions自定义配置功能

    • 如果是@GlideModule注册,则会直接在GeneratedAppGlideModuleImpl创建对象,并执行相应方法,如果是manifest注册,则会到Glide初始化流程去进行处理。

    好的,现在Glide反射的GeneratedAppGlideModuleImpl以及了解了,那么接下来看看使用:

    Glide.java
    
    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;
    }
    

    接着看 checkAndInitializeGlide(context, annotationGeneratedModule),经过层层调用,最终:

    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()) {
        manifestModules = new ManifestParser(applicationContext).parse();
      }
    
      //移除需要排除的GlideModule 
      ...
      for (com.bumptech.glide.module.GlideModule module : manifestModules) {
        module.applyOptions(applicationContext, builder);
      }
    
      //针对manifest 和 注解两种注册方式分别调用其applyOptions和registerComponents
      if (annotationGeneratedModule != null) {
        annotationGeneratedModule.applyOptions(applicationContext, builder);
      }
    
      //通过GlideBuilder做一系列初始化工作
      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;
    }
    

    这里针对manifest 和 注解两种注册方式分别调用其applyOptions和registerComponents来触发自定义配置和组件。

    二、Registry机制

    前面介绍了,registerComponents中是通过Registry对组件进行注册的,这里简单了解下Registry机制。
    Registry初始化时机是在Glide的构造方法中,并且在那会添加一批默认的组件。
    Registry本身的意义是组件根据功能进行灵活挂载。它只是作为一个入口类,具体功能会由如下具体Registry来处理:

    • ModelLoaderRegistry 注册ModelLoader
    • EncoderRegistry 注册Encoder
    • ResourceDecoderRegistry 注册ResourceDecoder
    • ResourceEncoderRegistry 注册ResourceEncoder
    • DataRewinderRegistry 注册DataRewinder
    • TranscoderRegistry 注册ResourceTranscoder
    • ImageHeaderParserRegistry 注册ImageHeaderParser

    相关类介绍:

    • ModelLoader 由ModelLoaderFactory创建,作用是经由内部类LoadData将复杂数据模型转通过DataFetcher转换成需要的DataClass。
    • Encoder 将通用T持久化到本地cache
    • ResourceDecoder 解码Resource
    • ResourceEncoder 将Bitmap和对应Drawable持久化到本地cache
    • DataRewinder 对流进行重置数据起点
    • ResourceTranscoder 对Resource进行转换
    • ImageHeaderParser 图片头解析

    以替换网络请求OKHTTP为例来介绍:

    Registry.java

    registry.replace(
           GlideUrl.class,   //Class<Model> modelClass ,GlideUrl对应的是一种Key,表示http/https url的字符串包装器。
           InputStream.class, //Class<Data> dataClass, 数据类型
           new OkHttpUrlLoader.Factory() //ModelLoaderFactory<? extends Model, ? extends Data> factory)  初始化了OkHttpClient
    modelLoaderRegistry.replace(modelClass, dataClass, factory);
    );
    

    ModelLoaderRegistry.java

        @NonNull Class<Model> modelClass,
       @NonNull Class<Data> dataClass,
       @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
      tearDown(multiModelLoaderFactory.replace(modelClass, dataClass, factory));//tearDown在OkHttpUrlLoader没做逻辑
      cache.clear();
    }
    

    MultiModelLoaderFactory

    @NonNull
    synchronized <Model, Data> List<ModelLoaderFactory<? extends Model, ? extends Data>> replace(
        @NonNull Class<Model> modelClass,
       @NonNull Class<Data> dataClass,
       @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
      List<ModelLoaderFactory<? extends Model, ? extends Data>> removed =
          remove(modelClass, dataClass);//删除以前的组件
      append(modelClass, dataClass, factory);//添加当前新的组件
      return removed;
    }
    
    synchronized <Model, Data> void append(
        @NonNull Class<Model> modelClass,
       @NonNull Class<Data> dataClass,
       @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory) {
      add(modelClass, dataClass, factory, /*append=*/ true);
    }
    
    private final List<Entry<?, ?>> entries = new ArrayList<>();
    private <Model, Data> void add(
        @NonNull Class<Model> modelClass,
       @NonNull Class<Data> dataClass,
       @NonNull ModelLoaderFactory<? extends Model, ? extends Data> factory,
       boolean append) {
      Entry<Model, Data> entry = new Entry<>(modelClass, dataClass, factory);
      entries.add(append ? entries.size() : 0, entry);
    }
    

    最终以Entry的形式添加到MultiModelLoaderFactory的ArrayList中。

    再举个例子:

    registry..prepend(
        Registry.BUCKET_BITMAP, //String bucket : bitmap
        InputStream.class,//Class<Data> dataClass
        Bitmap.class,//Class<TResource> resourceClass
        new StreamAnimatedBitmapDecoder(bitmapDecoder) //ResourceDecoder<Data, TResource> decoder
        decoderRegistry.prepend(bucket, decoder, dataClass, resourceClass);//ResourceDecoderRegistry
    );
    

    最大区别是最后传入的是个ResourceDecoder。

    ResourceDecoderRegistry.java

    private final List<String> bucketPriorityList = new ArrayList<>();
    private final Map<String, List<Entry<?, ?>>> decoders = new HashMap<>();
    public synchronized <T, R> void prepend(
        @NonNull String bucket,
       @NonNull ResourceDecoder<T, R> decoder,
       @NonNull Class<T> dataClass,
       @NonNull Class<R> resourceClass) {
      getOrAddEntryList(bucket).add(0, new Entry<>(dataClass, resourceClass, decoder));
    }
    
    @NonNull
    private synchronized List<Entry<?, ?>> getOrAddEntryList(@NonNull String bucket) {
      if (!bucketPriorityList.contains(bucket)) {
        // Add this unspecified bucket as a low priority bucket.
       bucketPriorityList.add(bucket);
      }
    
      List<Entry<?, ?>> entries = decoders.get(bucket);
    
      if (entries == null) {
        entries = new ArrayList<>();
       decoders.put(bucket, entries);
      }
      return entries;
    }
    

    最终以Entry的形式保留在ResourceDecoderRegistry的map中。

    后续是如何用的,参考后面的文章。

    参考:

    https://blog.csdn.net/weixin_34368949/article/details/88032953

    相关文章

      网友评论

          本文标题:图片框架 - Glide自定义配置和组件及Registry机制

          本文链接:https://www.haomeiwen.com/subject/fyvuhktx.html