上一章说到了Glide第一步配置Glide.with(context),返回统一的RequestManager,这个时候这个RequestManager具备了,生命周期监控的能力,详情请看 杨说:Glide 生命周期监听 这里我们开始将第二步,请求的配置
Glide.with(fragment)
.load(url)
.into(imageView);
目录
一、创建RequestBuilder
二、配置占位符
三、配置选项
四、过渡选项
五、缩略图
六、变换
七、缓存
八、总结
一 创建RequestBuilder
with()方法返回RequestManager后调用load(url)方法,这个方法有很多重载方法
RequestManager.java
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
public RequestBuilder<Drawable> load(@Nullable File file) {
return asDrawable().load(file);
}
public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
public RequestBuilder<Drawable> load(@Nullable URL url) {
return asDrawable().load(url);
}
public RequestBuilder<Drawable> load(@Nullable byte[] model) {
return asDrawable().load(model);
}
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
他们都是统一调用了asDrawable(),传入需要
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
//这里创建了RequestBuilder,RequestBuilder使用建造者模式构建请求的所有参数
return new RequestBuilder<>(glide, this, resourceClass, context);
}
创建RequestBuilder的代码
RequestBuilder.java
protected RequestBuilder(
@NonNull Glide glide,
RequestManager requestManager,
Class<TranscodeType> transcodeClass,
Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.glideContext = glide.getGlideContext();
initRequestListeners(requestManager.getDefaultRequestListeners());
apply(requestManager.getDefaultRequestOptions());
}
requestManager.getDefaultRequestListeners()获取的是glide外部配置的RequestListeners,他是在创建RequestManager的时候被赋值的,CopyOnWriteArrayList是线程安全的List通过读写锁保证线程安全
RequestManager.java
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
····
defaultRequestListeners =
new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
···
}
initRequestListeners(requestManager.getDefaultRequestListeners());将外部配置的RequestListener添加到RequestBuilder监听列表中
RequestBuilder.java
private void initRequestListeners(List<RequestListener<Object>> requestListeners) {
for (RequestListener<Object> listener : requestListeners) {
addListener((RequestListener<TranscodeType>) listener);
}
}
public RequestBuilder<TranscodeType> addListener(
@Nullable RequestListener<TranscodeType> requestListener) {
if (requestListener != null) {
if (this.requestListeners == null) {
this.requestListeners = new ArrayList<>();
}
this.requestListeners.add(requestListener);
}
return this;
}
requestManager.getDefaultRequestOptions(); 获取请求配置,他也是在创建RequestManager的时候被赋值的,通过原型模式复制请求选项
RequestManager.java
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
····
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
···
}
protected synchronized void setRequestOptions(@NonNull RequestOptions toSet) {
requestOptions = toSet.clone().autoClone();
}
BaseRequestOption.java
public T clone() {
try {
BaseRequestOptions<?> result = (BaseRequestOptions<?>) super.clone();
result.options = new Options();
result.options.putAll(options);
result.transformations = new CachedHashCodeArrayMap<>();
result.transformations.putAll(transformations);
result.isLocked = false;
result.isAutoCloneEnabled = false;
return (T) result;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
apply(requestManager.getDefaultRequestOptions()); 将请求选项添加到RequestBuilder中
RequestBuilder.java
public RequestBuilder<TranscodeType> apply(@NonNull BaseRequestOptions<?> requestOptions) {
Preconditions.checkNotNull(requestOptions);
return super.apply(requestOptions);
}
BaseRequestOptions.java 它是RequestBuilder的父类
public T apply(@NonNull BaseRequestOptions<?> o) {
if (isAutoCloneEnabled) {
return clone().apply(o);
}
BaseRequestOptions<?> other = o;
···
//上面是系列的赋值操作,使用的是位计算方式
fields |= other.fields;
//添加到选项中
options.putAll(other.options);
return selfOrThrowIfLocked();
}
创建RequestBuilder就可以配置Glide的所有的配置了比如图形的变换,是否缓存等
二 配置占位符
Glide.with(this)
.load(url)
.placeholder(R.drawable.holder) //正在请求时被展示,没有设置error和,url为null也展示
.error(R.drawable.error) //出错时展示,没有设置fallback,URL为null展示
.fallback(R.drawable.fallback) //fallback是URL为null的时候展示
.into(iv_activity)
placeholder(R.drawable.holder)
BaseRequestOptions.java
//设置图片选项
public T placeholder(@Nullable Drawable drawable) {
if (isAutoCloneEnabled) {
return clone().placeholder(drawable);
}
//复制placeholderDrawable
this.placeholderDrawable = drawable;
fields |= PLACEHOLDER;
placeholderId = 0;
fields &= ~PLACEHOLDER_ID;
return selfOrThrowIfLocked();
}
private T selfOrThrowIfLocked() {
if (isLocked) {
throw new IllegalStateException("You cannot modify locked T, consider clone()");
}
//返回当前对象
return self();
}
error(R.drawable.error)
BaseRequestOptions.java
public T error(@Nullable Drawable drawable) {
if (isAutoCloneEnabled) {
return clone().error(drawable);
}
//errorPlaceholder 赋值errorPlaceholder
this.errorPlaceholder = drawable;
fields |= ERROR_PLACEHOLDER;
this.errorId = 0;
fields &= ~ERROR_ID;
//返回当前对象
return selfOrThrowIfLocked();
}
fallback(R.drawable.fallback)
BaseRequestOptions.java
public T fallback(@Nullable Drawable drawable) {
if (isAutoCloneEnabled) {
return clone().fallback(drawable);
}
//fallbackDrawable 赋值fallbackDrawable
this.fallbackDrawable = drawable;
fields |= FALLBACK;
fallbackId = 0;
fields &= ~FALLBACK_ID;
//返回当前对象
return selfOrThrowIfLocked();
}
三 配置选项
如果需要统一配置的话,那可以统一设置选项然后设置到Glide中
var option = RequestOptions().placeholder(ColorDrawable(Color.BLACK))
.error(ColorDrawable(Color.BLUE))
.fallback(ColorDrawable(Color.RED))
Glide.with(this)
.load(url)
.apply(option)
.into(iv_activity)
apply(option),接收外部设置的参数,建造者模式构建RequestOptions对象
RequestBuilder.java
public RequestBuilder<TranscodeType> apply(@NonNull BaseRequestOptions<?> requestOptions) {
Preconditions.checkNotNull(requestOptions);
return super.apply(requestOptions);
}
给所有的参数赋值
BaseRequestOptions.java
public T apply(@NonNull BaseRequestOptions<?> o) {
····
fields |= other.fields;
options.putAll(other.options);
return selfOrThrowIfLocked();
}
四 过渡选项
Glide.with(this)
.load(uri)
.transition(DrawableTransitionOptions())
.into(iv_activity)
transition(DrawableTransitionOptions())直接赋值给transitionOptions
RequestBuilder.java
public RequestBuilder<TranscodeType> transition(
@NonNull TransitionOptions<?, ? super TranscodeType> transitionOptions) {
this.transitionOptions = Preconditions.checkNotNull(transitionOptions);
isDefaultTransitionOptionsSet = false;
return this;
}
五 缩略图
Glide.with(this)
.load(uri)
.thumbnail(Glide.with(this).load(url))
.into(iv_activity)
thumbnail(Glide.with(this).load(url))接收一个RequestBuilder尺寸比要下载的图片小,加载速度会比大图快
RequestBuilder.java
public RequestBuilder<TranscodeType> thumbnail(
@Nullable RequestBuilder<TranscodeType> thumbnailRequest) {
this.thumbnailBuilder = thumbnailRequest;
return this;
}
六 变换
6.1 单个的变换
Glide.with(this)
.load(uri)
.transform(CircleCrop())
.into(iv_activity)
获取资源并修改它,然后返回被修改后的资源。transform(CircleCrop())接收一个Transformation接口类型的参数,gilde给我们提供了默认的一个实现类型,比如CircleCrop(),如果我们需要自定义可以继承BitmapTransformation(),需要复写equals(),hashCode(),updateDiskCacheKey()
BaseRequestOptions.java
public T transform(@NonNull Transformation<Bitmap> transformation) {
return transform(transformation, /*isRequired=*/ true);
}
T transform(@NonNull Transformation<Bitmap> transformation, boolean isRequired) {
if (isAutoCloneEnabled) {
return clone().transform(transformation, isRequired);
}
//创建了一个DrawableTransformation
DrawableTransformation drawableTransformation =
new DrawableTransformation(transformation, isRequired);
//这里分别创建了四个转换
transform(Bitmap.class, transformation, isRequired);
transform(Drawable.class, drawableTransformation, isRequired);
// TODO: remove BitmapDrawable decoder and this transformation.
// Registering as BitmapDrawable is simply an optimization to avoid some iteration and
// isAssignableFrom checks when obtaining the transformation later on. It can be removed without
// affecting the functionality.
transform(BitmapDrawable.class, drawableTransformation.asBitmapDrawable(), isRequired);
transform(GifDrawable.class, new GifDrawableTransformation(transformation), isRequired);
return selfOrThrowIfLocked();
}
transform(Bitmap.class, transformation, isRequired);四个变换调动的都是一个方法,分别把变换添加到transformations中,这是一个Map,复制后返回RequestBuilder
BaseRequestOptions.java
<Y> T transform(
@NonNull Class<Y> resourceClass,
@NonNull Transformation<Y> transformation,
boolean isRequired) {
if (isAutoCloneEnabled) {
return clone().transform(resourceClass, transformation, isRequired);
}
Preconditions.checkNotNull(resourceClass);
Preconditions.checkNotNull(transformation);
transformations.put(resourceClass, transformation);
fields |= TRANSFORMATION;
isTransformationAllowed = true;
fields |= TRANSFORMATION_ALLOWED;
// Always set to false here. Known scale only transformations will call this method and then
// set isScaleOnlyOrNoTransform to true immediately after.
isScaleOnlyOrNoTransform = false;
if (isRequired) {
fields |= TRANSFORMATION_REQUIRED;
isTransformationRequired = true;
}
return selfOrThrowIfLocked();
}
6.2 多重变换
BaseRequestOptions.java
public T transform(@NonNull Transformation<Bitmap>... transformations) {
if (transformations.length > 1) {
// 传参大于一个
return transform(new MultiTransformation<>(transformations), /*isRequired=*/ true);
} else if (transformations.length == 1) {
//传参1个跟调用单个变换方法
return transform(transformations[0]);
} else {
return selfOrThrowIfLocked();
}
}
transform(new MultiTransformation<>(transformations), /isRequired=/ true); 传参大于一个使用MultiTransformation变换,变换的时候会依次进程变换。然后继续调用单个变换方法
MultiTransformation.java
public Resource<T> transform(
@NonNull Context context, @NonNull Resource<T> resource, int outWidth, int outHeight) {
Resource<T> previous = resource;
for (Transformation<T> transformation : transformations) {
Resource<T> transformed = transformation.transform(context, previous, outWidth, outHeight);
if (previous != null && !previous.equals(resource) && !previous.equals(transformed)) {
previous.recycle();
}
previous = transformed;
}
return previous;
}
七 缓存
设置缓存策略
Glide.with(this)
.load(uri)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(iv_activity)
diskCacheStrategy(DiskCacheStrategy.ALL) DiskCacheStrategy.ALL 使用策略模式,定义不同的策略
public abstract class DiskCacheStrategy {
/**
* Caches remote data with both {@link #DATA} and {@link #RESOURCE}, and local data with {@link
* #RESOURCE} only.
*/
public static final DiskCacheStrategy ALL =
···
/** Saves no data to cache. */
public static final DiskCacheStrategy NONE =
···
/** Writes retrieved data directly to the disk cache before it's decoded. */
public static final DiskCacheStrategy DATA =
···
/** Writes resources to disk after they've been decoded. */
public static final DiskCacheStrategy RESOURCE =
···
/**
* Tries to intelligently choose a strategy based on the data source of the {@link
* com.bumptech.glide.load.data.DataFetcher} and the {@link
* com.bumptech.glide.load.EncodeStrategy} of the {@link com.bumptech.glide.load.ResourceEncoder}
* (if an {@link com.bumptech.glide.load.ResourceEncoder} is available).
*/
public static final DiskCacheStrategy AUTOMATIC =
····
/**
* Returns true if this request should cache the original unmodified data.
*
* @param dataSource Indicates where the data was originally retrieved.
*/
public abstract boolean isDataCacheable(DataSource dataSource);
/**
* Returns true if this request should cache the final transformed resource.
*
* @param isFromAlternateCacheKey {@code true} if the resource we've decoded was loaded using an
* alternative, rather than the primary, cache key.
* @param dataSource Indicates where the data used to decode the resource was originally
* retrieved.
* @param encodeStrategy The {@link EncodeStrategy} the {@link
* com.bumptech.glide.load.ResourceEncoder} will use to encode the resource.
*/
public abstract boolean isResourceCacheable(
boolean isFromAlternateCacheKey, DataSource dataSource, EncodeStrategy encodeStrategy);
/** Returns true if this request should attempt to decode cached resource data. */
public abstract boolean decodeCachedResource();
/** Returns true if this request should attempt to decode cached source data. */
public abstract boolean decodeCachedData();
}
将策略赋值给diskCacheStrategy
BaseRequestOptions
public T diskCacheStrategy(@NonNull DiskCacheStrategy strategy) {
if (isAutoCloneEnabled) {
return clone().diskCacheStrategy(strategy);
}
this.diskCacheStrategy = Preconditions.checkNotNull(strategy);
fields |= DISK_CACHE_STRATEGY;
return selfOrThrowIfLocked();
}
跳过缓存
Glide.with(this)
.load(uri)
.skipMemoryCache(true)
.into(iv_activity)
BaseRequestOptions.java
public T skipMemoryCache(boolean skip) {
if (isAutoCloneEnabled) {
return clone().skipMemoryCache(true);
}
this.isCacheable = !skip;
fields |= IS_CACHEABLE;
return selfOrThrowIfLocked();
}
八 总结
Glide通过建造者模式,和原型模式,配置各个请求参数构建RequestBuilder,也可以通过创建RequestOptions统一配置,在这步只是简单的赋值,并没有做实际的请求,转换。 Glide的配置也可能通过注解的方式设置,比如更换图片网络库,默认HttpURLConnection