final 코스메틱의 부울 값을 수정할 수 있습니까?

5591 단어 문제 레코드
기억력이 나쁜 것만 못하다.생활 속에서 필기를 많이 하면 자신을 편리하게 할 수 있을 뿐만 아니라 다른 사람도 편리하게 할 수 있다.
배경.
며칠 전에 테스트 학생이 이미지와 관련된 버그를 제기했다. 나는 코드를 검사하고 논리를 정리하며 로그를 치고 코드를 디버깅했다.아바타 디스플레이는 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(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)을 여러 번 사용하고 로그를 쳤는데 그 중에서 이런 상황이 발생했다.
    ... setImage, test = true
    ... onResourceReady, test = false

테스트 변수는final 유형으로 이론적으로 나온 로그는 모두true이거나 모두false이므로 하나의true,하나의false가 나타나서는 안 된다.설마 final 수식된boolean 값도 수정할 수 있는 건 아니겠지?
까닭
의심할 필요가 없습니다.final에 의해 수식된boolean 값은 수정할 수 없습니다.문제는 glide에 나타난다.glide 원본의 into 방법을 보았습니다 (glide 버전은 4.5):
    private > Y into(
      @NonNull Y target,
      @Nullable RequestListener 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 설정과 같고 캐시 건너뛰기 (isSkipMemory CacheWith CompletePrevious Request) 를 설정하지 않으면 이전의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(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의 구덩이이다.
총결산
간단한 문제지만 문제에 부딪히면 원본을 많이 보고 원본을 많이 분석하는 이치를 알려주세요.

좋은 웹페이지 즐겨찾기