好記性不如爛筆頭。生活中多作筆記,不只能夠方便本身,還能夠方便他人。緩存
前幾天,測試同窗提了個跟頭像有關的bug,我去檢查代碼,梳理邏輯,打log,調試代碼。頭像的顯示採用的是Glide庫的組件。大概的代碼邏輯以下:bash
private void setImage(ImageView imageView, String url, final boolean test) {
Log.d(TAG, "setImage, test = " + test);
Glide.with(this)
.asBitmap()
.load(url)
.into(new ImageViewTarget<Bitmap>(imageView) {
@Override
protected void setResource(@Nullable Bitmap resource) {
}
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
super.onResourceReady(resource, transition);
if (test) {
Log.d(TAG, "onResourceReady, test = " + test);
}
}
});
}
複製代碼
在不一樣的地方,調用了上面的方法(setImage)屢次,打log,其中出現這樣的一組狀況:ide
... setImage, test = true
... onResourceReady, test = false
複製代碼
test變量爲final類型,理論上打出來的log,要麼都是true,要麼都是false,不該該出現一個true一個false的啊。難道final修飾的boolean值也能夠被修改?測試
不用懷疑,被final修飾的boolean值是不能夠被修改的。問題出如今glide。查看了glide源碼的into方法(glide版本是4.5):ui
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
@NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
options = options.autoClone();
Request request = buildRequest(target, targetListener, options);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
複製代碼
仔細看源碼,就會發現這個地方:this
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
複製代碼
@Override
public boolean isEquivalentTo(Request o) {
if (o instanceof SingleRequest) {
SingleRequest<?> that = (SingleRequest<?>) o;
return overrideWidth == that.overrideWidth
&& overrideHeight == that.overrideHeight
&& Util.bothModelsNullEquivalentOrEquals(model, that.model)
&& transcodeClass.equals(that.transcodeClass)
&& requestOptions.equals(that.requestOptions)
&& priority == that.priority
// We do not want to require that RequestListeners implement equals/hashcode, so we don't // compare them using equals(). We can however, at least assert that the request listener // is either present or not present in both requests. && (requestListener != null ? that.requestListener != null : that.requestListener == null); } return false; } 複製代碼
若是當前request的配置跟以前的previous配置是同樣的,並且沒有設置跳過緩存(isSkipMemoryCacheWithCompletePreviousRequest),就會直接拿以前的previous去請求,當前構造的request就會回收了。問題就出在這裏url
private void setImage(ImageView imageView, String url, final boolean test) {
Log.d(TAG, "setImage, test = " + test);
Glide.with(this)
.asBitmap()
.load(url)
.into(new ImageViewTarget<Bitmap>(imageView) {
@Override
protected void setResource(@Nullable Bitmap resource) {
}
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
super.onResourceReady(resource, transition);
if (test) {
Log.d(TAG, "onResourceReady, test = " + test);
}
}
});
}
複製代碼
因此,上面的ImageViewTarget並非新構建的target,而是之前舊的那個,因此上面的test變量的值並非新傳入的,而是以前傳入的。OK,問題解決了,這是glide的一個坑。spa
雖然是個簡單問題,可是也告訴我一個道理,遇到問題,多看源碼,多分析源碼。調試