Glide源碼分析三——Target相關(guān)

Target相關(guān)

Target相關(guān)

通常我們是調(diào)用requestBuilder#into(ImageView)憾股,接下來(lái)看看环葵,ImageView是如果轉(zhuǎn)化為Target的咕缎。

// RequestBuilder.java
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    // ... 省略scaleType相關(guān)代碼

    // 可以看到是通過(guò)GlideContext構(gòu)建一個(gè)ViewTarget郭蕉,內(nèi)部是使用imageViewTargetFactory來(lái)構(gòu)建的
    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
}
// GlideContext.java

// 通過(guò)下方代碼分析劝赔,可以知道是在Glide的構(gòu)造函數(shù)中傳進(jìn)來(lái)的
private final ImageViewTargetFactory imageViewTargetFactory;

public GlideContext(
      ...
      @NonNull ImageViewTargetFactory imageViewTargetFactory,
      ...) {
    super(context.getApplicationContext());
    ...
    this.imageViewTargetFactory = imageViewTargetFactory;
    ...
}


public <X> ViewTarget<ImageView, X> buildImageViewTarget(ImageView imageView, Class<X> transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
// Glide.java
Glide(...){

    ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
    glideContext = new GlideContext(
            ...
            imageViewTargetFactory,
            ...);
}
    
// ImageViewTargetFactory.java
public class ImageViewTargetFactory {
  
  // 通過(guò)判斷不同的類型烘豹,實(shí)例化不同的ViewTarget
  public <Z> ViewTarget<ImageView, Z> buildTarget(
      @NonNull ImageView view, @NonNull Class<Z> clazz) {
    if (Bitmap.class.equals(clazz)) {
      return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
    } else {
      throw new IllegalArgumentException(
          "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
  }
}

通常我們是通過(guò)一個(gè)url去加載圖片的瓜贾,由上面RequestManger#load(string)代碼可以知道,RequestBuilder的transcodeClass是Drawable.class携悯,所以最后得到的target是DrawableImageViewTarget祭芦。

Glide源碼分析二——Request相關(guān)中的SingleRequest#begin()可知,如果沒(méi)有設(shè)置overrideWidth/overrideHeight憔鬼,會(huì)通過(guò)viewTarget#getSize(SizeReadyCallback)獲取大小龟劲,獲取大小后在回調(diào)SizeReadyCallback#onSizeReady()通知SingleRequest加載圖片。

public abstract class ViewTarget<T extends View, Z> extends BaseTarget<Z> {
        
    protected final T view;
    private final SizeDeterminer sizeDeterminer;
    
    public ViewTarget(@NonNull T view) {
        this.view = Preconditions.checkNotNull(view);
        sizeDeterminer = new SizeDeterminer(view);
    }
  
    public void getSize(@NonNull SizeReadyCallback cb) {
        sizeDeterminer.getSize(cb);
    }  
    
    
    static final class SizeDeterminer {
    
        private final View view;
        private final List<SizeReadyCallback> cbs = new ArrayList<>();
        private SizeDeterminerLayoutListener layoutListener;
        
        SizeDeterminer(@NonNull View view) {
            this.view = view;
        }
        
        void getSize(@NonNull SizeReadyCallback cb) {
          int currentWidth = getTargetWidth();
          int currentHeight = getTargetHeight();
          // 如果view已經(jīng)可以獲取大小了逊彭,則回調(diào)SizeReadyCallback#onSizeReady(w,h)通知加載圖片
          if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
            cb.onSizeReady(currentWidth, currentHeight);
            return;
          }

          if (!cbs.contains(cb)) {
            cbs.add(cb);
          }
          if (layoutListener == null) {
            
            // 通過(guò)添加PreDrawListener來(lái)獲取大小咸灿,獲取大小后會(huì)回調(diào)SizeReadyCallback#onSizeReady(w,h)通知加載圖片
            ViewTreeObserver observer = view.getViewTreeObserver();
            layoutListener = new SizeDeterminerLayoutListener(this);
            observer.addOnPreDrawListener(layoutListener);
          }
        }
        
        // 獲取view的高度
        private int getTargetHeight() {
          int verticalPadding = view.getPaddingTop() + view.getPaddingBottom();
          LayoutParams layoutParams = view.getLayoutParams();
          int layoutParamSize = layoutParams != null ? layoutParams.height : PENDING_SIZE;
          return getTargetDimen(view.getHeight(), layoutParamSize, verticalPadding);
        }
        
        private int getTargetDimen(int viewSize, int paramSize, int paddingSize) {
          
          int adjustedParamSize = paramSize - paddingSize;
          
          // layoutParam中的Size可用就用paramSize
          if (adjustedParamSize > 0) {
            return adjustedParamSize;
          }
          
          // 如果view申請(qǐng)了繪制(例如調(diào)用了requestLayout),則返回0(無(wú)效尺寸侮叮,后面會(huì)去測(cè)量)
          if (waitForLayout && view.isLayoutRequested()) {
            return PENDING_SIZE;
          }

          // 如果view已經(jīng)有了寬高避矢,則返回view的寬高
          int adjustedViewSize = viewSize - paddingSize;
          if (adjustedViewSize > 0) {
            return adjustedViewSize;
          }

          // 如果view沒(méi)有申請(qǐng)繪制,且尺寸是wrap_content,則返回屏幕寬高的最大值
          if (!view.isLayoutRequested() && paramSize == LayoutParams.WRAP_CONTENT) {
            
            return getMaxDisplayLength(view.getContext());
          }

          // 不滿足上述條件則返回?zé)o效尺寸
          return PENDING_SIZE;
        }
        
        
        void checkCurrentDimens() {
          if (cbs.isEmpty()) {
            return;
          }

          int currentWidth = getTargetWidth();
          int currentHeight = getTargetHeight();
          if (!isViewStateAndSizeValid(currentWidth, currentHeight)) {
            return;
          }

          // 獲取到view的大小后审胸,通過(guò)SizeReadyCallback#onSizeReady(w,h)通知加載圖片
          notifyCbs(currentWidth, currentHeight);
          
          // 回調(diào)完后清除之前創(chuàng)建的PreDrawListener和添加的SizeReadyCallback
          clearCallbacksAndListener();
        }
        
        
        private static final class SizeDeterminerLayoutListener
        implements ViewTreeObserver.OnPreDrawListener {
          private final WeakReference<SizeDeterminer> sizeDeterminerRef;

          SizeDeterminerLayoutListener(@NonNull SizeDeterminer sizeDeterminer) {
            sizeDeterminerRef = new WeakReference<>(sizeDeterminer);
          }

          @Override
          public boolean onPreDraw() {
            // 這時(shí)可以正常獲取到大小了亥宿,通過(guò)SizeDeterminer去獲取大小
            SizeDeterminer sizeDeterminer = sizeDeterminerRef.get();
            if (sizeDeterminer != null) {
              sizeDeterminer.checkCurrentDimens();
            }
            return true;
          }
        }
        
    }

}

ViewTarget通過(guò)SizeDeterminer獲取大小,當(dāng)view已經(jīng)有大小或可以通過(guò)LayoutPrams獲取大小時(shí)砂沛,直接回調(diào)烫扼;否則通過(guò)添加PreDrawListener來(lái)獲取大小,之后再回調(diào)碍庵。

public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
    implements Transition.ViewAdapter {
    
  // 其他onLoadXxx(...)都差不多
  @Override
  public void onLoadStarted(@Nullable Drawable placeholder) {
    super.onLoadStarted(placeholder);
    setResourceInternal(null);
    setDrawable(placeholder);
  }
  
  // 當(dāng)資源獲取成功時(shí)會(huì)回調(diào)此方法
  @Override
  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
  }
  
  private void setResourceInternal(@Nullable Z resource) {
    // 通知子類加載資源映企,例如DrawableImageViewTarget就是直接調(diào)用ImageView#setImageDrawable(resource)
    setResource(resource);
    // 如果資源是動(dòng)畫的話,則開(kāi)啟動(dòng)畫
    maybeUpdateAnimatable(resource);
  }
  
  @Override
  public void setDrawable(Drawable drawable) {
    view.setImageDrawable(drawable);
  }
  
  private void maybeUpdateAnimatable(@Nullable Z resource) {
    if (resource instanceof Animatable) {
      animatable = (Animatable) resource;
      animatable.start();
    } else {
      animatable = null;
    }
  }
  
  protected abstract void setResource(@Nullable Z resource);
    
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末静浴,一起剝皮案震驚了整個(gè)濱河市堰氓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苹享,老刑警劉巖双絮,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異得问,居然都是意外死亡囤攀,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門宫纬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)焚挠,“玉大人,你說(shuō)我怎么就攤上這事哪怔⌒担” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵认境,是天一觀的道長(zhǎng)胚委。 經(jīng)常有香客問(wèn)我,道長(zhǎng)叉信,這世上最難降的妖魔是什么亩冬? 我笑而不...
    開(kāi)封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮硼身,結(jié)果婚禮上硅急,老公的妹妹穿的比我還像新娘。我一直安慰自己佳遂,他們只是感情好营袜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著丑罪,像睡著了一般荚板。 火紅的嫁衣襯著肌膚如雪凤壁。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天跪另,我揣著相機(jī)與錄音拧抖,去河邊找鬼。 笑死免绿,一個(gè)胖子當(dāng)著我的面吹牛唧席,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嘲驾,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼淌哟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了辽故?” 一聲冷哼從身側(cè)響起绞绒,我...
    開(kāi)封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎榕暇,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喻杈,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡彤枢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筒饰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缴啡。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瓷们,靈堂內(nèi)的尸體忽然破棺而出业栅,到底是詐尸還是另有隱情,我是刑警寧澤谬晕,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布碘裕,位于F島的核電站,受9級(jí)特大地震影響攒钳,放射性物質(zhì)發(fā)生泄漏帮孔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一不撑、第九天 我趴在偏房一處隱蔽的房頂上張望文兢。 院中可真熱鬧,春花似錦焕檬、人聲如沸姆坚。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)兼呵。三九已至兔辅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間萍程,已是汗流浹背幢妄。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茫负,地道東北人蕉鸳。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像忍法,于是被迫代替她去往敵國(guó)和親潮尝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容