Glide設置默認圖片后setImageBitmap,setImageResource失效問題

復現(xiàn)場景

在適配器中添加了一個條件,path為空就去加載本地圖片,不為空就使用Glide去加載圖片,偽代碼實現(xiàn)如下:

 @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
         if(path==null){
               imageView.setImageResource(R.drawable.my_image)
         }else{
               Glide.with(this).load(path).apply( RequestOptions().placeholder(R.drawable.place).error(R.drawable.error)).into(imageView)
           }
    }

咋一看沒啥問題,當path為一個無效地址的時候,imageView會顯示error的圖片,但是當path為null的時候,發(fā)現(xiàn)imageView沒有顯示my_image,還是顯示的error圖片,打斷點發(fā)現(xiàn)imageView.setImageResource(R.drawable.my_image)這句代碼是執(zhí)行了的,但為什么會失效呢?

解決方案

先來說一下解決方案,如果對出現(xiàn)原因(從源碼層面分析)感興趣可以繼續(xù)往下看

1.使用Glide.with(this).clear(imageView)關閉失敗重試
2.使用Glide加載本地圖片,不使用原生Api:

Glide.with(imageView).load(R.drawable.my_image).into(imageView)

出現(xiàn)原因

Glide內(nèi)部有加載失敗重試機制,當?shù)谝淮渭虞d失敗,重試機制就會啟動,這時imageView.setImageResource(R.drawable.my_image)也同步執(zhí)行了,但是當重試機制執(zhí)行完畢后,Glide發(fā)現(xiàn)圖片最終還是加載失敗,所以會將error中設置的圖片又添加到imageView上去,所以并不是imageView.setImageResource(R.drawable.my_image)這句代碼失效了,而是Glide又重新設置了一遍。

我們可以來瞅一眼源碼,我們知道圖片加載失敗是有一個回調(diào)的,所以從回調(diào)入手:
先找到RequestListener回調(diào):

public interface RequestListener<R> {


  boolean onLoadFailed(
      @Nullable GlideException e, Object model, Target<R> target, boolean isFirstResource);


  boolean onResourceReady(
      R resource, Object model, Target<R> target, DataSource dataSource, boolean isFirstResource);
}

隨后找到onLoadFailed實現(xiàn)類SingleRequest:

  /**
   * A callback method that should never be invoked directly.
   */
  @Override
  public void onLoadFailed(GlideException e) {
    onLoadFailed(e, Log.WARN);
  }

  private void onLoadFailed(GlideException e, int maxLogLevel) {
    stateVerifier.throwIfRecycled();
    int logLevel = glideContext.getLogLevel();
    if (logLevel <= maxLogLevel) {
      Log.w(GLIDE_TAG, "Load failed for " + model + " with size [" + width + "x" + height + "]", e);
      if (logLevel <= Log.INFO) {
        e.logRootCauses(GLIDE_TAG);
      }
    }

    loadStatus = null;
    status = Status.FAILED;

    isCallingCallbacks = true;
    try {
      //TODO: what if this is a thumbnail request?
      if ((requestListener == null
          || !requestListener.onLoadFailed(e, model, target, isFirstReadyResource()))   //可以看到listence的接口調(diào)用是在這里,返回值決定了是否往下調(diào)用邏輯
          && (targetListener == null
          || !targetListener.onLoadFailed(e, model, target, isFirstReadyResource()))) {
        setErrorPlaceholder();
      }
    } finally {
      isCallingCallbacks = false;
    }

    notifyLoadFailed();  //這里會重試一次
  }

可以看到這里會先有一個requestListener的接口調(diào)用,這里requestListener其實就是我們的listence監(jiān)聽功能:

Glide.with(imageView).load(url).listener(new RequestListener<Drawable>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                return false;
            }

            @Override
            public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                return false;
            }
        })

只有返回false才會去調(diào)用setErrorPlaceholder()方法,看一下:

  private void setErrorPlaceholder() {
    if (!canNotifyStatusChanged()) {
      return;
    }

    Drawable error = null;
    if (model == null) {
      error = getFallbackDrawable();
    }
    // Either the model isn't null, or there was no fallback drawable set.
    if (error == null) {
      error = getErrorDrawable();
    }
    // The model isn't null, no fallback drawable was set or no error drawable was set.
    if (error == null) {
      error = getPlaceholderDrawable();
    }
    target.onLoadFailed(error);  //target就是我們設置進去的ImageView
  }

在看一下我們的onLoadFailed實現(xiàn):

  @Override
  public void onLoadFailed(@Nullable Drawable errorDrawable) {
    super.onLoadFailed(errorDrawable);
    setResourceInternal(null);
    setDrawable(errorDrawable);
  }

所以setErrorPlaceholder方法的作用就是把我們設置的error圖片設置給我們放進去的ImageView上
我們回到onLoadFailed方法中,發(fā)現(xiàn)最后調(diào)用了notifyLoadFailed()方法,這個方法是干嘛的呢,看一下源碼:

  private void notifyLoadFailed() {
    if (requestCoordinator != null) {
      requestCoordinator.onRequestFailed(this);
    }
  }

是一個接口,我們看一下它的實現(xiàn),是在ErrorRequestCoordinator中:

    if (!request.equals(error)) {
      if (!error.isRunning()) {
        error.begin();
      }
      return;
    }

    if (parent != null) {
      parent.onRequestFailed(this);
    }

我們發(fā)現(xiàn)調(diào)用了一個熟悉的方法,begin(),研究過源碼的都知道,Glide都會在這個接口實現(xiàn)開始異步加載的方法,所以在這里又會去開始異步加載圖片

所以,走一圈下來,大致的流程就是這樣子:
SingleRequest類中先調(diào)用begin開始異步加載圖片->加載失敗->onLoadFailed()->調(diào)用notifyLoadFailed()方法重試(內(nèi)部會判斷是否需要重試)->需要加載重試->begin

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 【Android 庫 Glide】 引用 Android圖片加載框架最全解析(一),Glide的基本用法Andro...
    Rtia閱讀 5,890評論 0 22
  • 概述 剛才有說到,有些朋友覺得Glide 4相對于Glide 3改動非常大,其實不然。之所以大家會有這種錯覺,是因...
    陳曉松快點跑閱讀 2,316評論 0 14
  • 最近在做群聊功能,使用了環(huán)信的SDK,在環(huán)信demo中無意之中看到了glide框架,簡單了解后,發(fā)現(xiàn)這個框架很強(...
    guggle閱讀 2,259評論 1 7
  • 學習來源:郭霖大師博客地址 1、圖片加載框架挺多,如Volley、Glide、Picasso、Fresco、本次是...
    子謙寶寶閱讀 1,825評論 0 6
  • 一、簡介 在泰國舉行的谷歌開發(fā)者論壇上,谷歌為我們介紹了一個名叫Glide的圖片加載庫,作者是bumptech。這...
    天天大保建閱讀 7,753評論 2 28

友情鏈接更多精彩內(nèi)容