版本号:4.9.0
一.基本概念
1.Model
数据来源,不管是imgURL、资源文件还是本地文件,在Glide中封装为Model。
2.Data
原始数据,获取Model之后,处理成原始数据,一般就是输入流,在Glide中封装为Data。
3.Resource
解码之后的资源,比如将输入流解码成Bitmap。
4.TransformedResource
Resource变换之后的资源,比如:裁剪。
5.TranscodedResource
转码之后的资源,将解码之后的资源转换成统一的格式。
5.Target
图片显示的目标。
加载流程
二.基本使用
Glide.with(this)
.load(imgUrl)
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.ic_launcher)
.override(300,300)//指定图片的尺寸
.skipMemoryCache(true)//不使用内存缓存
.diskCacheStrategy(DiskCacheStrategy.ALL)//磁盘缓存:缓存所有版本的
.centerCrop() //设置缩放类型
.priority(Priority.HIGH)//指定优先级,尽可能处理优先级高的
.into(imageView)
最核心的方法其实就是:
with()、load()、into()
,创建请求对象,指定数据源,设置显示目标。其他的方法都是一些图片的设置和缓存设置等。下面分别来看一下这三个方法:
1.with()方法
该方法有很多的重载,传入的参数分别是context、activity、fragmentActivity、fragment
,下面以参数为context
的方法为为例分析:
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
with()
方法返回一个RequestManager对象,该对象是请求管理的对象,是通过RequestManagerRetriever的get()
方法获取的,RequestManagerRetriever就是用来生产RequestManager对象的。下面看一下get()
方法:
@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);
}
如果不是在UI线程或者context是Application,就会调用
getApplicationManager(context);
方法,否则就会对context
分类调用对应的方法。getApplicationManager(context);
方法就是通过Glide创建一个RequestManager对象。
下面看一下参数为activity
的方法:
public class RequestManagerRetriever implements Handler.Callback{
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
//如果是在子线程中调用的,使用的还是Application的上下文
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
//通过fragmentGet()方法创建RequestManager对象
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
@Deprecated
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
//创建一个没有UI的Fragment,Fragment可以监听Activity的生命周期,所以Glide通过该Fragment来间接的
//监听对应的生命周期
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
}
Glide是没法直接监听Activity的生命周期的,这里创建了一个没有UI的Fragment,通过它来间接的监听对应的生命周期,下面看一下是如果实现监听的:
public class RequestManagerFragment extends Fragment {
//ActivityFragmentLifecycle类是生命周期回调的管理类
private final ActivityFragmentLifecycle lifecycle;
......
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
......
}
ActivityFragmentLifecycle它实现了LifeCycle接口,会将LifecycleListener的接口加入到ActivityFragmentLifecycle类中的Set集合中,当RequestManagerFragment的生命周期的方法触发时,会调用ActivityFragmentLifeCycle的相应方法。
public class RequestManager implements LifecycleListener,
ModelTypes<RequestBuilder<Drawable>> {
RequestManager(Glide glide,Lifecycle lifecycle, RequestManagerTreeNode treeNode,
RequestTracker requestTracker,ConnectivityMonitorFactory factory,Context context) {
this.glide = glide;
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.context = context;
......
if (Util.isOnBackgroundThread()) {
mainHandler.post(addSelfToLifecycle);
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
......
glide.registerRequestManager(this);
}
}
RequestManager实现了LifeCycleListener接口,在RequestManager的构造方法中会将创建的RequestManager对象加入到ActivityFragmentLifeCycle的管理LifeCycleListener接口的集合中去,所以当ActivityFragmentLifeCycle的相应的方法调用时就会调用RequestManager对象的相应方法
2.load()方法
可以看到
load()
方法也有很多的重载,因为数据的来源不同。下面以参数为Uri的方法为例分析:
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
asDrawable()
方法就是创建一个RequestBuilder实例,然后调用该实例的load()
方法,该方法最终会调用loadGeneric()
方法,该方法的作用就是给RequestBuilder的成员变量private Object model;
赋值。然后返回this
,形成链式调用。下面看一下RequestBuilder的成员变量:
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {
// Used in generated subclasses
protected static final RequestOptions DOWNLOAD_ONLY_OPTIONS =
new RequestOptions().diskCacheStrategy(DiskCacheStrategy.DATA).priority(Priority.LOW)
.skipMemoryCache(true);
private final Context context;
private final RequestManager requestManager;
private final Class<TranscodeType> transcodeClass;
private final Glide glide;
private final GlideContext glideContext;
@NonNull
@SuppressWarnings("unchecked")
private TransitionOptions<?, ? super TranscodeType> transitionOptions;
@Nullable private Object model;
// model may occasionally be null, so to enforce that load() was called, put a boolean rather
// than relying on model not to be null.
@Nullable private List<RequestListener<TranscodeType>> requestListeners;
@Nullable private RequestBuilder<TranscodeType> thumbnailBuilder;
@Nullable private RequestBuilder<TranscodeType> errorBuilder;
@Nullable private Float thumbSizeMultiplier;
private boolean isDefaultTransitionOptionsSet = true;
private boolean isModelSet;
private boolean isThumbnailBuilt;
}
//RequestBuilder的父类
public abstract class BaseRequestOptions<T extends BaseRequestOptions<T>> implements Cloneable {
......
private int fields;
private float sizeMultiplier = 1f;
@NonNull
private DiskCacheStrategy diskCacheStrategy = DiskCacheStrategy.AUTOMATIC;
@NonNull
private Priority priority = Priority.NORMAL;
@Nullable
private Drawable errorPlaceholder;
private int errorId;
@Nullable
private Drawable placeholderDrawable;
private int placeholderId;
private boolean isCacheable = true;
private int overrideHeight = UNSET;
private int overrideWidth = UNSET;
@NonNull
private Key signature = EmptySignature.obtain();
private boolean isTransformationRequired;
private boolean isTransformationAllowed = true;
@Nullable
private Drawable fallbackDrawable;
private int fallbackId;
@NonNull
private Options options = new Options();
@NonNull
private Map<Class<?>, Transformation<?>> transformations = new CachedHashCodeArrayMap<>();
@NonNull
private Class<?> resourceClass = Object.class;
private boolean isLocked;
@Nullable
private Resources.Theme theme;
private boolean isAutoCloneEnabled;
private boolean useUnlimitedSourceGeneratorsPool;
private boolean onlyRetrieveFromCache;
private boolean isScaleOnlyOrNoTransform = true;
private boolean useAnimationPool;
......
}
从RequestBuilder及其父类的成员变量可以看到,关于Glide的配置的属性都在这里面,比如:
overrideHeight 、overrideWidth 、placeholderDrawable、priority
等。在该类的构造方法中会对这些属性有默认的初始化赋值。
3.into()方法
在上面配置好imageUrl和一些参数设置之后调用into()
方法,就可以实现显示图片的功能了。下面看一个该方法的代码:
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
//判断是否在主线程,否则跑出异常
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
根据ImageView的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()方法,传入了一个Target参数
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
从上述代码中可以看出,
into()
方法必须要主线程中调用,否则抛出异常。在该方法中将传入的ImageView对象封装成了Target对象通过glideContext.buildImageViewTarget(view, transcodeClass)
方法,下面就看一下该方法的具体实现:
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
//如果调用了asBitmap()方法
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} 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)");
}
}
}
以BitmapImageViewTarget为例,就是对ImageView封装了一层,调用对应的方法其实就是调用ImageView的相应方法。比如如下所示:
public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> {
......
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
......
}
创建Target实例以后就会调用参数为该实例的
into()
方法,下面看一下该方法的实现:
private <Y extends Target<TranscodeType>> Y into(@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,Executor callbackExecutor) {
......
//构建请求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//获取上一个请求
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
//如果是相同的请求直接复用
request.recycle();
......
if (!Preconditions.checkNotNull(previous).isRunning()) {
......
previous.begin();
}
return target;
}
requestManager.clear(target);
//target与request绑定,通过View.setTag(obj)
target.setRequest(request);
requestManager.track(target, request);
return target;
}
下面继续看一下requestManager.track(target, request);
方法:
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
最终调用
requestTracker.runRequest(request);
方法来执行请求,继续看一下该请求的实现:
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
又会调用request.begin();
来开始请求:
@Override
public synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
......
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());
}
......
}
如果设置了图片的大小
override(300,300)
,图片的宽高就使用没有,没有设置的话,就使用ImageView的宽高target.getSize()
,最终都会调用onSizeReady()
方法来设置图片大小以及开始真正的请求。
public synchronized void onSizeReady(int width, int height) {
......
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
......
loadStatus =
//开始真正的请求
engine.load(参数省略...);
......
}
通过engine的
load()
方法来执行请求:
public synchronized <R> LoadStatus load(参数省略...){
......
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob);
......
}
public synchronized void start(DecodeJob<R> decodeJob) {
//decodeJob是一个Runable
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}