glide已经出来好几年了,在项目加载图片中也经常使用,我自己也打算做一个总结,通过源码阅读和调试,分析一下它的实现方案。glide相关的所有文章都将基于glide 4.5.0源码。本文先通过一段简单代码,介绍Glide图片加载流程,然后再基于各个知识点进行分析。使用方式如下,在gradle中引入。
compile "com.github.bumptech.glide:glide:4.5.0"
annotationProcessor "com.github.bumptech.glide:compiler:4.5.0"
添加配置类,继承AppGlideModule,可以在该类中配置GlideBuilder,也可以注册Register,这些配置在创建Glide对象时使用。
@GlideModule
public class GlideModuleConfig extends AppGlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
}
@Override
public void registerComponents(Context context, Glide glide, Registry registry) {
super.registerComponents(context, glide, registry);
}
@Override
public boolean isManifestParsingEnabled() {
return false;
}
}
为该类添加@GlideModule注解,android apt注解处理器在编译glide源码时,将根据该注解自动生成GlideApp类文件,生成的位置在build/generated/source/apt/debug目录下面。
glide自动生成的类文件.png 在Activity组件中,我们执行下面的方法,一行代码可以实现图片加载,这是一个最简单的加载方式,包括with,load和into方法,从表面看,就是关联上下文,加载地址和ImageView目标视图。GlideApp.with(this).load(url).into(imageView);
显示图片。
屏幕快照.png
下面从这三个方法开始分析,glide是如何一步步将一个url图片显示到ImageView上的。
with方法
首先,该方法返回一个GlideRequests对象,方法参数可以接收View、Context、Activity、Fragment和FragmentActivity。 屏幕快照.png这些方法都会调用Glide的with方法,参数也支持这些。
//GlideApp的with方法。
public static GlideRequests with(@NonNull View arg0) {
return (GlideRequests) Glide.with(arg0);
}
//Glide的with方法。
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
在调用Glide的getRetriever方法时,传入Context, 视图获取它的Context,Fragment获取它的Activity,其他直接传入。返回一个RequestManagerRetriever对象,它在Glide单例对象内部。
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
return Glide.get(context).getRequestManagerRetriever();
}
下面是利用Context来获取Glide单例,完成配置初始化,可以看出,Glide框架也有一个可配置的单例对象控制全局,其他开源框架比如Okhttp也类似。
Glide类内部静态私有对象
private static volatile Glide glide
@NonNull
public static Glide get(@NonNull Context context) {//context是View的Context
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);//只初始化一次,创建glide对象
}
}
}
return glide;
}
Glide初始化一次,checkAndInitializeGlide方法,调用initializeGlide方法,创建一个GlideBuilder建造者对象,GlideBuilder向用户开放,添加配置。
private static void initializeGlide(@NonNull Context context) {
initializeGlide(context, new GlideBuilder());
}
//创建Glide。
@SuppressWarnings("deprecation")
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
//获取全局Context。
Context applicationContext = context.getApplicationContext();
//创建一个GeneratedAppGlideModuleImpl对象。
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
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;
}
iterator.remove();
}
}
//获取RequestManagerFactory工厂。
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
builder.setRequestManagerFactory(factory);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {
//用户初始化builder模块,在AppGlideModule的继承类applyOptions方法中实现。
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
//建造者方法创建Glide对象
Glide glide = builder.build(applicationContext);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}
首先,创建一个com.bumptech.glide.GeneratedAppGlideModuleImpl实例对象,它也是在编译时自动生成的Java类,继承GeneratedAppGlideModule,继承AppGlideModule。
GeneratedAppGlideModuleImpl的内部包含AppGlideModule,它就是我们在文章开头自定义的GlideModuleConfig配置类,有同一个父类AppGlideModule。
然后,执行GeneratedAppGlideModuleImpl的applyOptions方法和registerComponents方法,进入我们自定义配置类的这两个方法,将GlideBuilder暴漏出来,设置配置项。
最后,GlideBuilder的build方法创建Glide实例。
我们再回到上面的getRetriever方法,该方法将返回Glide内部引用的RequestManagerRetriever,下面是它在GlideBuilder#build方法的初始化。
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
再回到上面Glide的with方法,如果之前已经创建过Glide实例,将直接获取内部RequestManagerRetriever,然后,通过它的get方法,获取RequestManager请求管理器。
public RequestManager get(@NonNull View view) {
//非主线程时
if (Util.isOnBackgroundThread()) {
return get(view.getContext().getApplicationContext());
}
Activity activity = findActivity(view.getContext());
if (activity == null) {
return get(view.getContext().getApplicationContext());
}
if (activity instanceof FragmentActivity) {
Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
return fragment != null ? get(fragment) : get(activity);
}
android.app.Fragment fragment = findFragment(view, activity);
if (fragment == null) {
return get(activity);
}
return get(fragment);
}
Glide的with方法支持各种参数,get方法也一样,支持View,Fragment,Activity,Context参数。以参数View为例,若是非主线程调用或该View的Activity已经是空,根据全局Context去get。其他情况,根据Activity或Fragment去get。
最终,有三个地方利用工厂去创建RequestManager。全局Context,获取它内部的RequestManager对象。
private RequestManager getApplicationManager(@NonNull Context context) {
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
如果过是主线程Activity或Fragment组件加载,且他们存在时,调用fragmentGet或supportFragmentGet方法创建,这两种都是将创建的RequestManager对象保存在RequestManagerFragment和SupportRequestManagerFragment中。
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
@NonNull
private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
@Nullable Fragment parentHint) {
//parentHint是加载图片的那个Fragment。
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
RequestManager由RequestManagerFactory工厂创建,该工厂在GlideBuilder,上面的initializeGlide方法,GeneratedAppGlideModuleImpl重写了工厂获取类,GeneratedRequestManagerFactory工厂类,自动生成的Java类。
@Override
GeneratedRequestManagerFactory getRequestManagerFactory() {
return new GeneratedRequestManagerFactory();
}
final class GeneratedRequestManagerFactory implements RequestManagerRetriever.RequestManagerFactory {
@Override
public RequestManager build(Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode,
Context context) {
return new GlideRequests(glide, lifecycle, treeNode, context);
}
}
该工厂获取的是一个GlideRequests对象,它继承RequestManager。回到GlideApp的with方法,将它转换成GlideRequests对象,GlideRequests也是自动生成的类。
到这里,with方法就结束了,总之,就是根据当前请求的组件或视图上下文,返回一个GlideRequests请求实体管理者。
load方法
前面的with方法,得到的是一个GlideRequests对象,下面我们调用这个对象的load方法,它支持多种数据源,如url、文件、Bitmap、字节数组、Drawable、资源Id。 加载源.png我们以url进行分析,看一下GlideRequest的load(url)方法做了哪些事情。它的父类是RequestManager,调用父类的load方法。
//GlideRequest方法
public GlideRequest<Drawable> load(@Nullable String arg0) {
return (GlideRequest<Drawable>) super.load(arg0);
}
//RequestManager方法
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
RequestManager#asDrawable方法。创建一个RequestBuilder对象,代表一个请求实体。
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
首先,<ResourceType>资源类型resourceClass是Drawable类型。请求实体构造方法传入glide对象,请求管理器,资源类型(Drawable类型)和Context。
类似方法还包括asGif,资源类型GifDrawable,asBitmap,资源类型Bitmap,asFile,资源类型File。
然后,创建RequestBuilder请求实体,该实体泛型对应具体资源类型。回到load方法,调用RequestBuilder<Drawable>实体的load方法。
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model){
this.model = model;
isModelSet = true;
return this;
}
该方法返回RequestBuilder<Drawable>自己本身,主要目的是将加载资源保存在内部model对象中,在我们举例中保存String类型的url。
再次回到最初GlideRequest的load方法,将返回的请求实体类型转换成GlideRequest<Drawable>。GlideRequest继承RequestBuilder。GlideRequest也是自动生成的Java类。
到这里,load方法也介绍完了,它比较简单,总的来说,就是由GlideRequests实体管理者,根据请求资源的地址创建一个具体的GlideRequest请求实体。
into方法
glide简单示例三个方法中的最后一个,调用的是GlideRequest<Drawable>的into方法,父类RequestBuilder的into方法,它的入参是ImageView。
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
RequestOptions requestOptions = this.requestOptions;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
...
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions);
}
首先,根据ImageView的ScaleType类型,设置RequestOptions的配置项,ScaleType类型判断相关代码没有全部贴出来。
然后,调用GlideContext的buildImageViewTarget方法,上面介绍过,在请求实体RequestBuilder构造方法,将Glide单例传入,每个请求实体内部引用GlideContext。
buildImageViewTarget方法,创建一个ViewTarget<ImageView, X>,这里的传入的transcodeClasss是Drawable类型,通过内部的ImageViewTargetFactory工厂类,创建的ViewTarget有两种类型,这里是DrawableImageViewTarget。此外,如果资源类型transcodeClasss是Bitmap,创建的是BitmapImageViewTarget类型。
这个transcodeClass类型就是我们创建RequestBuilder对象时,传入的resourceClass类型,即Drawable。根据不同的class类型,创建不同的ViewTarget对象。
最后,在成功创建ViewTarget后,调用RequestBuilder<Drawable>的另一个into方法。
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
@NonNull RequestOptions options) {
//在into之前,调用load方法设置model,并设置isModelSet为true。
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
options = options.autoClone();
Request request = buildRequest(target, targetListener, options);
...
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
首先,调用buildRequest方法,创建一个Request请求,它是一个接口,代表为Target加载资源的请求,将该请求设置到ViewTarget内部。下面看一下创建一个真正的请求实现类的方法。
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
RequestOptions requestOptions) {
//调用内部buildRequestRecursive方法,将requestOptions提取传入
return buildRequestRecursive(
target,
targetListener,
...其他参数);
}
传入参数包括ViewTarget,RequestListener和RequestOptions。Request创建的代码较多,不详细分析了。还是按照上面最简单的图片加载方式示例,只有with,load,into三个方法,调试一下,最后调用的位置是RequestBuilder的obtainRequest方法,创建SingleRequest。
private Request obtainRequest(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
RequestOptions requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight) {
return SingleRequest.obtain(
context,
glideContext,
...//参数较多);
}
通过SingleRequest的obain静态方法创建实例,实例的init方法初始化传入的这些参数。
创建SingleRequest实例后,再回到RequestBuilder<Drawable>的into方法,然后,调用请求管理器的track方法,上面介绍过,在请求实体RequestBuilder构造方法,将请求管理器传入,每个请求实体内部引用RequestManager。
void track(Target<?> target, Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
TargetTracker中存储一个Target的集合,将Target加入集合,然后执行RequestTracker的runRequest方法。
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
将请求加入内部Set集合,如果isPaused暂停标志,将请求加入pendingRequests列表,RequestTracker是一个请求追踪器。在未暂停情况下,调用SingleRequest的begin方法开始请求。
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
...
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
}
在前面介绍过的创建RequestBuilder<Drawable>时,会将加载资源(网络是url)保存在内部model对象中,该对象后初始化给SingleRequest,因此,如果是空,异常onLoadFailed方法。
初始状态是Status.PENDING,若已经改变成COMPLETE,直接回调返回。否则,将状态变更WAITING_FOR_SIZE。
最后,看一下onSizeReady方法,该方法通过SingleRequest内部的加载引擎Engine去load加载,返回一个状态LoadStatus。
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
//状态必须是WAITING_FOR_SIZE。
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;//状态更新RUNNING
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
loadStatus = engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,...);//load参数较多
if (status != Status.RUNNING) {
loadStatus = null;
}
}
该方法主要加载引擎Engine的load方法,传入的参数大部分是请求配置参数。
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
...
ResourceCallback cb) {
long startTime = LogTime.getLogTime();
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
return null;
}
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
return null;
}
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
return new LoadStatus(cb, current);
}
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
...
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
创建一个EngineKey,若支持内存缓存,首先,loadFromActiveResources方法,根据key,在ActiveResources中获取资源EngineResource。其次,loadFromCache方法,同样支持内存缓存。以上这两种情况都是从内存获取数据,onResourceReady回调表明来源是MEMORY_CACHE。
若内存缓存中未找到,就需要从磁盘缓存或者网络中获取了。EngineJobFactory工厂和DecodeJobFactory工厂分别创建两个Job,他们是EngineJob和DecodeJob。下面是任务开始,EngineJob的start方法。
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
willDecodeFromCache方法,是否从Disk缓存中获取,内部有四个GlideExecutor线程池,根据条件,选择一个线程池执行任务。DecodeJob是一个Runnable任务,该任务获取图片,可以从资源中,文件缓存,或者网络中获取。
本文先介绍到这里,文章篇幅过大,关于DecodeJob任务执行的过程下次介绍。
任重而道远
网友评论