鍍金池/ 教程/ Android/ 目標(biāo)
配置
Generated API
轉(zhuǎn)換
選項(xiàng)
過(guò)渡效果
關(guān)于Glide
緩存
調(diào)試
目標(biāo)
占位符
下載和設(shè)置
入門指南

目標(biāo)

Glide中的目標(biāo)作為請(qǐng)求跟請(qǐng)求者之間的傳遞者。目標(biāo)負(fù)責(zé)顯示占位符,加載的資源以及為每個(gè)請(qǐng)求確定合適的尺寸。最常用目標(biāo)是使用ImageView顯示占位符,Drawable和Bitmap的ImageViewTarget。用戶還可以實(shí)現(xiàn)自己的目標(biāo),或者對(duì)任何可用的基類進(jìn)行子類化。

指定目標(biāo)

into(Target)方法不僅用于啟動(dòng)每個(gè)請(qǐng)求,同時(shí)也可以指定將要接收請(qǐng)求結(jié)果的目標(biāo)。Glide提供了一個(gè)輔助方法給into(ImageView),其采用ImageView并把它包裝在目標(biāo)于適合所請(qǐng)求的資源類型。

為了方便使用自定義目標(biāo),這些into()方法返回提供給他們的目標(biāo):

Target<Bitmap> target = Glide.with(fragment)
        .asBitmap()
        .load(url)
        .into(imageView);
...
// Some time later:
Glide.with(fragment).clear(target);

目標(biāo)和自動(dòng)取消

目標(biāo)可以并且通常應(yīng)該被重新用于相同的地方顯示的每個(gè)后續(xù)請(qǐng)求。重新使用目標(biāo)允許Glide在新加載啟動(dòng)時(shí)自動(dòng)取消并且重新使用之前負(fù)載的資源。未能重新使用目標(biāo)可能會(huì)導(dǎo)致之前請(qǐng)求中的資源替換較新的請(qǐng)求。

自定義目標(biāo)

重新使用自定義目標(biāo)的一種簡(jiǎn)單方法是簡(jiǎn)單地將其作為實(shí)例變量:

private class WidgetHolder {
  private final Fragment fragment;
  private final Target<Widget> widgetTarget;

  public WidgetHolder(Fragment fragment, Widget widget) {
    this.fragment = fragment;
    widgetTarget = new CustomWidgetTarget(widget);
  }

  public void showInWidget(Uri uri) {
    Glide.with(fragment)
        .load(uri)
        .into(widgetTarget);
  }
}

Glide能夠使用getRequest()和setRequest()方法查找和取消對(duì)目標(biāo)的請(qǐng)求。這意味著所有自定義的目標(biāo)都必須實(shí)現(xiàn)這些方法。最簡(jiǎn)單的方法是進(jìn)行子類化BaseTarget。

ViewTargets

一些自定義的目標(biāo)還可以提供更智能的getRequest()和setRequest()實(shí)現(xiàn),避免嚴(yán)格要求重新使用目標(biāo)。例如,ViewTarget使用Android Framework的getTag()和setTag()方法:

@Override
public Request getRequest() {
    return (Request) view.getTag();
}

@Override
public void setRequest(Request request) {
    view.setTag(request);
}

由于標(biāo)簽是View的屬性,因此新加載的ViewTargets可以查找和取消/重新使用先前ViewTargets的請(qǐng)求。因此,當(dāng)使用into(ImageView)或ViewTarget的子類加載到視圖中時(shí),您可以為每個(gè)加載傳遞新的目標(biāo):

@Override
public void onBindViewHolder(ViewHolder vh, int position) {
  int resourceId = resourceIds.get(position)
  Glide.with(fragment)
      .load(resourceId)
      .into(new CustomViewTarget(vh.imageView));

尺寸

默認(rèn)情況下,Glide使用由Targets提供的getSize()大小作為請(qǐng)求的目標(biāo)大小。這樣做可以讓Glide選擇適當(dāng)?shù)膗rl,downsample,crop和轉(zhuǎn)換適當(dāng)?shù)膱D像,以盡量減少內(nèi)存使用,并確保負(fù)載盡可能快。

最簡(jiǎn)單的實(shí)現(xiàn)方式是在getSize()方法中立即調(diào)用回調(diào)函數(shù):

@Override
public void getSize(SizeReadyCallback cb) {
  cb.onSizeReady(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
}

您還可以將尺寸傳遞給您的Target的構(gòu)造函數(shù),并將這些尺寸提供給回調(diào):

public class CustomTarget<T> implements Target<T> {
  private final int width;
  private final int height;

  public CustomTarget(int width, int height) {
    this.width = width;
    this.height = height;
  }

  ...

  @Override
  public void getSize(SizeReadyCallback cb) {
    cb.onSizeReady(width, height);
  }
}

查看目標(biāo)

ViewTarget實(shí)現(xiàn)了getSize()方法,通過(guò)檢查View的屬性或者使用onPreDrawListener在渲染之前立即測(cè)量視圖來(lái)實(shí)現(xiàn)。我們采用下面的邏輯:

  1. 如果任一視圖的尺寸設(shè)置的值>0,則使用這些尺寸。
  2. 如果任一視圖的尺寸設(shè)置成WRAP_CONTENT,則使用屏幕的寬度或高度。
  3. 如果至少有一個(gè)視圖的尺寸的值<=0而不是WRAP_CONTENT,則添加一個(gè)OnPreDrawListener來(lái)監(jiān)聽(tīng)布局。

WRAP_CONTENT

請(qǐng)注意,Glide不能很好的處理WRAP_CONTENT,這是因?yàn)閷?duì)于我們來(lái)說(shuō)很難清楚用戶的意圖,特別是要求轉(zhuǎn)換時(shí)。

我們可以看作WRAP_CONTENT是用戶請(qǐng)求原始的未修改的圖像,但是這樣做在我們加載大圖像時(shí)有內(nèi)存溢出的風(fēng)險(xiǎn)。另外,特別是視圖不會(huì)脫離屏幕,因此Android框架可能會(huì)最終縮小任何加載成功的全分辨率圖像。

使用屏幕尺寸,我們至少可以對(duì)超大圖像進(jìn)行降低采樣,而不會(huì)完全忽略用戶的請(qǐng)求。

應(yīng)用視圖大小

一般來(lái)說(shuō),當(dāng)在其加載的視圖上設(shè)置顯示dp大小時(shí),Glide提供了最快的和最可預(yù)測(cè)的結(jié)果。然而,當(dāng)不可能這樣時(shí),Glide還為布局權(quán)重,MATCH_PARENT和其他相對(duì)尺寸提供了強(qiáng)大的支持OnPreDrawListeners。最后,如果這些都沒(méi)有設(shè)置,Glide應(yīng)該為WRAP_CONTENT提供了合理的行為。

備選方案

如果在任何情況下,Glide似乎都會(huì)使View大小錯(cuò)誤,您可以隨時(shí)通過(guò)擴(kuò)展ViewTarget和實(shí)現(xiàn)自己的邏輯來(lái)手動(dòng)覆蓋大小,或者通過(guò)使用RequestOptions中的override()方法。

下一篇:配置