接上篇蝗敢,代碼依然是4.11.0版本逗堵。
一叶眉、自定義配置和組件
1.1 Glide如何實現(xiàn)自定義配置和組件
/**
* 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
常用設(shè)置項:
setMemoryCache() //用于配置Glide的內(nèi)存緩存策略慷妙,默認配置是LruResourceCache僻焚。
setBitmapPool()//用于配置Glide的Bitmap緩存池,默認配置是LruBitmapPool膝擂。
setDiskCache()//用于配置Glide的硬盤緩存策略虑啤,默認配置是InternalCacheDiskCacheFactory。
setDiskCacheService()//用于配置Glide讀取緩存中圖片的異步執(zhí)行器架馋,默認配置是FifoPriorityThreadPoolExecutor狞山,也就是先入先出原則。
setResizeService()//用于配置Glide讀取非緩存中圖片的異步執(zhí)行器叉寂,默認配置也是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 自定義配置和組件的調(diào)用流程
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,那就去找對應(yīng)生成文件的Porcessor
對應(yīng)的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基礎(chǔ)(二)-注解
運行時注解簡而言之就是在編譯器生成一個類文件堤结,類的內(nèi)容通過javapoet組裝出來搏讶。這個不是本文的重點,點到為止霍殴,那么來看看
生成后的內(nèi)容:
@SuppressWarnings("deprecation")
final class GeneratedAppGlideModuleImpl extends GeneratedAppGlideModule {
private final CustomAppGlideModule appGlideModule;
GeneratedAppGlideModuleImpl() {
//CustomAppGlideModule 實現(xiàn)了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 實現(xiàn)了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();
}
}
這里總結(jié)下本地的配置在GeneratedAppGlideModuleImpl生成的規(guī)則:
AppGlideModule 只能實現(xiàn)1個来庭,但是LibraryGlideModule可以實現(xiàn)多個妒蔚。LibraryGlideModule只有registerComponents自定義組件功能,而AppGlideModule在LibraryGlideModule基礎(chǔ)上增加了applyOptions自定義配置功能
如果是@GlideModule注冊月弛,則會直接在GeneratedAppGlideModuleImpl創(chuàng)建對象肴盏,并執(zhí)行相應(yīng)方法,如果是manifest注冊帽衙,則會到Glide初始化流程去進行處理菜皂。
好的,現(xiàn)在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)恍飘,經(jīng)過層層調(diào)用,最終:
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 和 注解兩種注冊方式分別調(diào)用其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 和 注解兩種注冊方式分別調(diào)用其applyOptions和registerComponents來觸發(fā)自定義配置和組件谴垫。
二章母、Registry機制
前面介紹了,registerComponents中是通過Registry對組件進行注冊的翩剪,這里簡單了解下Registry機制乳怎。
Registry初始化時機是在Glide的構(gòu)造方法中,并且在那會添加一批默認的組件前弯。
Registry本身的意義是組件根據(jù)功能進行靈活掛載蚪缀。它只是作為一個入口類,具體功能會由如下具體Registry來處理:
- ModelLoaderRegistry 注冊ModelLoader
- EncoderRegistry 注冊Encoder
- ResourceDecoderRegistry 注冊ResourceDecoder
- ResourceEncoderRegistry 注冊ResourceEncoder
- DataRewinderRegistry 注冊DataRewinder
- TranscoderRegistry 注冊ResourceTranscoder
- ImageHeaderParserRegistry 注冊ImageHeaderParser
相關(guān)類介紹:
- ModelLoader 由ModelLoaderFactory創(chuàng)建恕出,作用是經(jīng)由內(nèi)部類LoadData將復(fù)雜數(shù)據(jù)模型轉(zhuǎn)通過DataFetcher轉(zhuǎn)換成需要的DataClass询枚。
- Encoder 將通用T持久化到本地cache
- ResourceDecoder 解碼Resource
- ResourceEncoder 將Bitmap和對應(yīng)Drawable持久化到本地cache
- DataRewinder 對流進行重置數(shù)據(jù)起點
- ResourceTranscoder 對Resource進行轉(zhuǎn)換
- ImageHeaderParser 圖片頭解析
以替換網(wǎng)絡(luò)請求OKHTTP為例來介紹:
Registry.java
registry.replace(
GlideUrl.class, //Class<Model> modelClass ,GlideUrl對應(yīng)的是一種Key剃根,表示http/https url的字符串包裝器哩盲。
InputStream.class, //Class<Data> dataClass, 數(shù)據(jù)類型
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
);
最大區(qū)別是最后傳入的是個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中廉油。
后續(xù)是如何用的,參考后面的文章苗傅。
參考:
https://blog.csdn.net/weixin_34368949/article/details/88032953