简介
由于在Android项目开发中我们经常会用到图片加载,你会选择什么第三库来加载图片,今天让我们来学习一下Glide图片加载库的源码吧,之前文章有讲解到Glide的简单使用。
简单使用
这里就不说添加依赖那些了,大家可以看官方文档,或者我之前的文章Glide的简单使用,但是版本现在最新的版本是4.8.0
。
接下来我们看看Glide是如何加载图片的,如下代码
public class MainActivity extends AppCompatActivity {
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.imageView);
Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}
}
我们通过上述代码中得到,Glide加载的使用方式是非常简单的。好了根据这句代码我们进行Glide的源码分析吧。
Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
通过上述代码我们知道Glide中的with(this)调用的方法中携带了Activity或者Fragment的上下文对象其作用是:用于绑定该上下文对象的生命周期,如Activity或者Fragment的声明周期。代码如下:共有6个不同参数构造方法,返回静态的RequestManager
,用于加载图片。
//contex对象
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. 用于启动加载的给定activity上下文的RequestManager
*/
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
//FragmentActivity 上下文对象
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
// fragment上下文对象
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
//V4的fragment对象
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
// view对象
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
RequestManager
是通过RequestManagerRetriever
的get()
方法获取,而get() 方法中的参数就是我们上述代码传递过来的上下文对象。
然后getRetriever(Context context)
方法返回的对象是RequestManagerRetriever
,如下代码所示。
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// 这里通过方法checkNotNull() 校验携带的上下文是否为null,如果是null将抛出空指针异常
Preconditions.checkNotNull(
context,
"You cannot start a load on a not yet attached View or a Fragment where getActivity() "
+ "returns null (which usually occurs when getActivity() is called before the Fragment "
+ "is attached or after the Fragment is destroyed).");
return Glide.get(context).getRequestManagerRetriever();
}
如果校验上下文对象并无异常,则通过Glide.get(context).getRequestManagerRetriever();
返回 RequestManagerRetriever
对象。
//这里使用的是双重校验单例方式初始化Glide实例
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
//检查并初始化Glide
checkAndInitializeGlide(context);
}
}
}
return glide;
}
在checkAndInitializeGlide(context)方法中的initializeGlide(context,builder)
方法进行初始化,实例化唯一的Glide实例(双重校验单例方式获取)。
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();//获取长连接上下文对象
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();//通过注解方式生成GeneratedAppGlideModule
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
//加载Glide Module
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();
//清除已经存在的Glide Module
while (iterator.hasNext()) {
com.bumptech.glide.module.GlideModule current = iterator.next();
if (!excludedModuleClasses.contains(current.getClass())) {
continue;
}
...
//清除
iterator.remove();
}
}
...
}
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
//设置Glide Builder 用于建造 Glide
builder.setRequestManagerFactory(factory);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {
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.glide = glide;
}
有上面我们知道要获取到RequestManager
是通过Glide.get(context).getRequestManagerRetriever();
调用get()
方法。我们来看看getRequestManagerRetriever()
方法。
//返回RequestManagerRetrieve对象
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever;
}
现在我得到了RequestManagerRetrieve
以后通过RequestManagerRetrieve.get(context)
方法就可以获取到我们的RequestManager
了。
这里需要注意的是get()
方法下面有不同之处。FragmentActivity
或者是``
@NonNull
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
public RequestManager get(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) { ///当前是不是后台线程
return get(activity.getApplicationContext()); //从新调用上边get()方法
} else {
assertNotDestroyed(activity); //通过断言判断是否是已经销毁的上下文对象
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
supportFragmentGet()
方法得到RequestManager
对象,当前Activity不能是Finished关闭状态。
// 获取RequestManager 对象
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
//无界面的Fragment,即SupportRequestManagerFragment
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
// 获取RequestManager
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
//获取Glide 实例
Glide glide = Glide.get(context);
//通过RequestManagerFactory构建RequestManager。
//current.getGlideLifecycle()获取生命周期,getRequestManagerTreeNode获取RequestManagerTreeNode
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
到这里我们已经得到了一个无界面的Fragment,即SupportRequestManagerFragment ,让请求和你的activity的生命周期同步。
接下来我们进行到调用load()
方法中,看看发生什么情况。我们知道调用load()
方法是RequestManager.class
,所以我们进入该类发现该类实现了LifecycleListener
和ModelTypes<T>
接口,而ModelTypes<T>
是我们所需的load()
方法的接口。
//表示回调是Activity生命周期的三个方法
public interface LifecycleListener {
void onStart();
void onStop();
void onDestroy();
}
而ModelTypes<T>
接口刚好是定义了load()
方法,如下
interface ModelTypes<T> {
//bitmap参数类型
T load(@Nullable Bitmap bitmap);
//drawable参数类型
T load(@Nullable Drawable drawable);
//string参数类型
T load(@Nullable String string);
//uri参数类型
T load(@Nullable Uri uri);
//file参数类型
T load(@Nullable File file);
//resourceId参数类型
T load(@RawRes @DrawableRes @Nullable Integer resourceId);
//url参数类型
T load(@Nullable URL url);
//byte[]参数类型
T load(@Nullable byte[] model);
//Object 参数类型
T load(@Nullable Object model);
}
当RequestManager
调用方法load()
代码如下,返回的是RequestBuilder<Drawable>
实例,该实例可以进行一些常用的操作,如占位符如:placeholder、error、fallback
等方式接下来我们会进行分析该占位符。
//返回一个请求的构建器RequestBuilder<Drawable>
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
我们进入asDrawable()
方法看看返回RequestBuilder<Drawable>
//默认情况下,可以返回android.graphics.drawable.BitmapDrawable或GifDrawable,但如果为其他Drawable子类注册了其他解码器,也可以返回任何子类。
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
//用于加载给定资源类的新请求构建器:RequestBuilder<ResourceType>
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
得到RequestBuilder<ResourceType>
以后调用load()
,而该类实现的接口是ModelTypes<RequestBuilder<TranscodeType>>
,这里区别于RequestManager
实现的接口参数ModelTypes<RequestBuilder<Drawable>>
,说明在这里已经进行了转码了,从Drawable
发生了转码。
@Override
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
@Override
public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
return loadGeneric(bitmap)
.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE)); //diskCacheStrategyOf(DiskCacheStrategy.NONE)表示磁盘缓存策略
//apply方法在load(@RawRes @DrawableRes @Nullable Integer resourceId) 、load(@Nullable Drawable drawable)、load(@Nullable Bitmap bitmap)调用
}
//返回当前RequestBuilder<TranscodeType>对象
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
接下来我们进入into()
方法。
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread(); // 检查是否为后台线程也就是UI线程,必须在主线程调用Into()方法
Preconditions.checkNotNull(view); //当前view是否为空,是空就报空指针异常。
RequestOptions requestOptions = this.requestOptions;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
//在此方法中克隆,以便如果我们使用此RequestBuilder加载到View中,然后加载到不同的目标中,我们不会保留基于先前View的缩放类型应用的转换。
//获取view的ScaleType
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
//调用into(),返回ViewTarget<ImageView, TranscodeType> 对象
return into(
glideContext.buildImageViewTarget(view, transcodeClass),//构建ImageViewTarget,这个类扩展自BaseTarget.class
/*targetListener=*/ null,
requestOptions);
}
在buildImageViewTarget(view, transcodeClass)
通过imageViewTargetFactory.buildTarget()
工厂方法来返回ViewTarget<ImageView, X>
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
通过ImageViewTargetFactory
工厂方法得到ViewTarget
实例,这个过程为后面设置图片加载view.setImageBitmap(resource);
使用。
public class ImageViewTargetFactory {
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view); //创建了BitmapImageViewTarget转换为ViewTarget
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
} } }
然后进入上述的into()
方法中,该方法构建了Request
对象实例过程并进行加载图片。如下代码
//返回ViewTarget<ImageView, TranscodeType>
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
@NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) { //是否调用load()方法标志
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
options = options.autoClone(); //设置自动克隆,加锁过程
//构造一个请求Request,通过构建请求递归方式返回Request,调用方法是buildRequestRecursive(), 构建缩略图buildThumbnailRequestRecursive()
//这个方法最终会调用到`SingleRequest.obtain()`并且初始化SingleRequest,而我们想要的Request对象就是SingleRequest返回的
Request request = buildRequest(target, targetListener, options);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous) //判断这个请求和之前的是否是一样的
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {//如果之前已经保存在内存缓存了则跳过内存缓存
request.recycle(); //回收request
//如果请求完成,则再次开始将确保重新传递结果,触发RequestListeners和Targets。 如果请求失败,则再次开始将重新启动请求,
//从而再次完成请求。 如果请求已在运行,我们可以让它继续运行而不会中断。
if (!Preconditions.checkNotNull(previous).isRunning()) {
//使用先前的请求而不是新请求来允许优化,例如跳过设置占位符,跟踪和取消跟踪目标,以及获取在单个请求中完成的视图维度。
previous.begin(); //启动异步加载
}
return target;
}
requestManager.clear(target); //清除target对象
target.setRequest(request); //设置此目标(View)保留的当前请求,不应在Glide外部调用
requestManager.track(target, request); //追踪请求操作
return target;
}
通过上面代码注解我们知道Request
初始化过程,并返回了SingleRequest
对象。我们进入 requestManager.track(target, request)
追踪方法,我要知道target是之前传递过来的View的对象转换而成的,在TargetTracker.class
中实现了生命周期LifecycleListener
接口,通过弱引用集合WeakHashMap
保存了target
对象(记得这个对象是View转换而成的),这里确保了在线程同步状态中执行。然后在requestTracker.runRequest(request);
方法中启动了给定了请求request.begin();
,在SingleRequest<R>.class
中实现了该接口,如下。
@Override
public void begin() {
assertNotCallingCallbacks(); //是否允许回调,如果是true则抛出异常无法在RequestListener或Target回调中启动或清除加载...
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) { //是否是有效尺寸
width = overrideWidth;
height = overrideHeight;
}
// 如果用户设置了回退可绘制,则仅记录更详细的日志级别,因为回退Drawable表示用户偶尔需要空模型。
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
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); // DataSource.MEMORY_CACHE表示从内存缓存中获取数据,该方法表示发布资源,并发布完成并设置为noll :engine.release(resource); Engine.class负责启动负载并管理活动和缓存资源 这个方法重点
return;
}
status = Status.WAITING_FOR_SIZE; //等待给予目标的回调以确定目标尺寸
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight); //目标图片大小读取,这个方法中开始调用了请求方法,追踪到Engine.load,设置一下缓存策略,并从磁盘,缓存中读取
} else {
target.getSize(this); //获取大小
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable()); //加载开始
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}}
从上述代码中成功加载的状态跟踪方法到这里,我们从开始的加载Resource
的对象是ImageView
通过转换为最终的target
到这里我们将弄明白了这个加载情况,代码如下。
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
....
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
if (requestListeners != null) {
for (RequestListener<R> listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onResourceReady(result, model, target, dataSource, isFirstResource);
}
}
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation); //target最后调用加载资源文件读取
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess(); //通知加载成功!
}
我们回再到into()
方法中,由于ImageViewTarget<Z>
扩展自抽象类ViewTarget<ImageView, Z>
而ViewTarget<ImageView, Z>
扩展自BaseTarget<Z>
该父类实现了Target<Z>
接口,所以ImageViewTarget<Z>
重写了该方法,而DrawableImageViewTarget.class
扩展自ImageViewTarget<Z>
,这样最后将会调用setResource()
方法
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}}
private void setResourceInternal(@Nullable Z resource) {
setResource(resource);
maybeUpdateAnimatable(resource);
}
public class DrawableImageViewTarget extends ImageViewTarget<Bitmap> {
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
}
总结
接下来我们将细分模块进行讲解,本篇只是大致的讲解Glide加载的过程,知道加载完成的步骤,还有某些重要的模块这里没有讲解到。如占位符、缓存、变化等等,下篇见分晓。
推荐
- 我的博客
- 大家可以到我的博客https://eirunye.github.io进行浏览相关文章,大家一起相互探讨技术。