Glide中的目標(biāo)作為請(qǐng)求跟請(qǐng)求者之間的傳遞者。目標(biāo)負(fù)責(zé)顯示占位符,加載的資源以及為每個(gè)請(qǐng)求確定合適的尺寸。最常用目標(biāo)是使用ImageView顯示占位符,Drawable和Bitmap的ImageViewTarget。用戶(hù)還可以實(shí)現(xiàn)自己的目標(biāo),或者對(duì)任何可用的基類(lèi)進(jìn)行子類(lèi)化。
into(Target)方法不僅用于啟動(dòng)每個(gè)請(qǐng)求,同時(shí)也可以指定將要接收請(qǐng)求結(jié)果的目標(biāo)。Glide提供了一個(gè)輔助方法給into(ImageView),其采用ImageView并把它包裝在目標(biāo)于適合所請(qǐng)求的資源類(lèi)型。
為了方便使用自定義目標(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)可以并且通常應(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)的一種簡(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)行子類(lèi)化BaseTarget。
一些自定義的目標(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的子類(lèi)加載到視圖中時(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);
}
}
ViewTarget實(shí)現(xiàn)了getSize()方法,通過(guò)檢查View的屬性或者使用onPreDrawListener在渲染之前立即測(cè)量視圖來(lái)實(shí)現(xiàn)。我們采用下面的邏輯:
請(qǐng)注意,Glide不能很好的處理WRAP_CONTENT,這是因?yàn)閷?duì)于我們來(lái)說(shuō)很難清楚用戶(hù)的意圖,特別是要求轉(zhuǎn)換時(shí)。
我們可以看作WRAP_CONTENT是用戶(hù)請(qǐng)求原始的未修改的圖像,但是這樣做在我們加載大圖像時(shí)有內(nèi)存溢出的風(fēng)險(xiǎn)。另外,特別是視圖不會(huì)脫離屏幕,因此Android框架可能會(huì)最終縮小任何加載成功的全分辨率圖像。
使用屏幕尺寸,我們至少可以對(duì)超大圖像進(jìn)行降低采樣,而不會(huì)完全忽略用戶(hù)的請(qǐ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()方法。