内容简介:前几天,测试同学提了个跟头像有关的bug,我去检查代码,梳理逻辑,打log,调试代码。头像的显示采用的是Glide库的组件。大概的代码逻辑如下:在不同的地方,调用了上面的方法(setImage)多次,打log,其中出现这样的一组情况:test变量为final类型,理论上打出来的log,要么都是true,要么都是false,不应该出现一个true一个false的啊。
前几天,测试同学提了个跟头像有关的bug,我去检查代码,梳理逻辑,打log,调试代码。头像的显示采用的是Glide库的组件。大概的代码逻辑如下:
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,其中出现这样的一组情况:
... setImage, test = true ... onResourceReady, test = false 复制代码
test变量为final类型,理论上打出来的log,要么都是true,要么都是false,不应该出现一个true一个false的啊。 难道final修饰的boolean值也可以被修改?
原因
不用怀疑,被final修饰的boolean值是不可以被修改的。问题出现在glide。查看了glide源码的into方法(glide版本是4.5):
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; } 复制代码
仔细看源码,就会发现这个地方:
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就会回收了。问题就出在这里
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的一个坑。
总结
虽然是个简单问题,但是也告诉我一个道理,遇到问题,多看源码,多分析源码。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Go 语言的布尔值
- Haskell:非严格的布尔运算
- 6. Go 语言数据类型:字典与布尔类型
- golang leetcode 1106 解析布尔表达式
- 6. Go语言中的字典与布尔类型
- C++函数修饰符总结
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
自己动手做iOS App
张子怡 / 电子工业出版社 / 2017-8 / 69.00
《自己动手做iOS App:从设计开发到上架App Store》为想要接触iOS 应用设计、开发的读者提供了由浅入深的详细指导。从iOS 应用制作的步骤是什么,应该使用什么软件,如何发布应用到App Store,到iOS 的设计理念是什么,如何正确书写Swift 语言,再到后端和客户端是如何交互运作的等,本书配合图示,精辟、直观地阐明了iOS 应用制作中的种种疑问。 如果你是一位第一次接触i......一起来看看 《自己动手做iOS App》 这本书的介绍吧!