Glide — 回調:定制view中使用SimpleTarget和ViewTarget
原文:Callbacks: SimpleTarget and ViewTarget for Custom View Classes
作者:Norman Peitek
翻譯:Dexter0218
前面3篇都是圍繞著優化Glide的流程和提升用戶體驗。下面的幾篇會如何使用Glide中的的回調技術。目前為止,我們總是假設加載圖片或Gif到ImageView上,但那并不適用所有的情況。本文將要介紹在沒有指定的ImageView時,著手獲取一個圖片的資源。
Glide 系列概覽
- 入門簡介
- 高級加載
- 適配器(ListView, GridView)
- 占位圖& 淡入淡出動畫
- 圖片大小 & 縮放
- 播放GIF & 視頻
- 緩存基礎
- 請求優先級
- 縮略圖
- 回調:定制view中使用SimpleTarget和ViewTarget
- 通知欄和桌面小控件的圖片加載
- 異常: 調試和報錯處理
- 自定義變換
- 用animate()定制動畫
- 整合網絡協議棧
- 用Modules定制Glide
- Glide Module 案例: 接受自簽名HTTPS證書
- Glide Module 案例: 自定義緩存
- Glide Module 案例: 通過加載自定義大小圖片優化
- 動態使用 Model Loaders
- 如何旋轉圖片
- 系列綜述
Glide中的回調:Target
目前為止,我們已經能夠很方便地使用Glide去加載圖片到ImageView中。在應用場景中,Glide隱藏了大量復雜的工作。Glide在后臺線程中處理了所有的網絡請求,一旦結果準備完畢,就會調用UI線程更新ImageVIew。
在這篇文章中,我們假設我們并沒有ImageView作為圖片加載的目標。我們只需要Bitmap本身。Glide提供了一個用Target獲取Bitmap資源的方法。Target只是用來回調,它會在所有的加載和處理完畢時返回想要的結果。
Glide提供了多種多樣有各自明確目的Target。在隨后的幾個小節了逐一介紹。我們先從SimpleTarget介紹。
SimpleTarget
我們看看代碼:
private SimpleTarget target = new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
// do something with the bitmap
// for demonstration purposes, let's just set it to an ImageView
imageView1.setImageBitmap( bitmap );
}
};
private void loadImageSimpleTarget() {
Glide
.with( context ) // could be an issue!
.load( eatFoodyImages[0] )
.asBitmap()
.into( target );
}
代碼的第一部分,創建一個target字段對象,里面定義了個方法,這個方法一旦Glide加載和處理完圖片將會被調用?;卣{方法傳回Bitmap作為參數,你可以在你所需要用的地方隨意使用這個Bitmap對象。
代碼的第二部分,表明了Glide里如何使用Target,明顯跟ImageView一樣!你可以傳遞一個Target或者ImageView作為參數到.into()方法里。Glide會神奇地將結果返回。這里有個不同點,我們添加了.asBitmap(),這會強制返回一個Bitmap對象。記住,Glide也可以加載Gif或視頻。為了防止在從網絡URL(可能是GIF)獲取Bitmap時,出現未知格式圖片沖突(期望是Bitmap),我們設置.asBitmap()去告訴Glide只有在資源是一個圖片是才算成功,其他的都算解析失敗。
使用Target注意事項
除了剛介紹的Target的回調系統的一個簡單版本,你要學會額外兩件事。
第一個是SimpleTarget對象的定義。java/Android可以允許你在.into()內匿名定義,但這會顯著增加在Glide處理完圖片請求前Android垃圾回收清理匿名target對象的可能性。最終,會導致圖片被加載了,但是回調永遠不會被調用。所以,請確保將你的回調定義為一個字段對象,防止被萬惡的Android垃圾回收給清理掉。
第二個關鍵部分是Glide的.with( context )。這個問題實際上是Glide一個特性問題:當你傳遞了一個context,例如當前app的activity,當activity停止后,Glide會自動停止當前的請求。這種整合到app生命周期內是非常有用的,但也是很難處理的。如果你的target是獨立于app的生命周期。這里的解決方案是使用application的context:.with( context.getApplicationContext() )
。當app自己停止運行的時候,Glide會只取消掉圖片的請求。請記住,再次提醒,如果你的請求需要在activity的生命周期以外,使用下面的代碼:
private void loadImageSimpleTargetApplicationContext() {
Glide
.with( context.getApplicationContext() ) // safer!
.load( eatFoodyImages[1]
.asBitmap()
.into( target2 );
}
特定大小的Target
另外一個潛在問題是Target沒有一個明確的大小。如果你傳遞一個ImageView作為.into()的參數,Glide會使用ImageView的大小來限制圖片的大小。例如如果要加載的圖片是1000x1000像素,但是ImageView的尺寸只有250x250像素,Glide會降低圖片到小尺寸,以節省處理時間和內存。顯然,由于target沒有具體大小,這對target并不起效。但是,如果你有個期望的具體大小,你可以增強回調。如果你知道圖片應當為多大,那么在你的回調定義里應當指明,以節省內存:
private SimpleTarget target2 = new SimpleTarget<Bitmap>( 250, 250 ) {
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
imageView2.setImageBitmap( bitmap );
}
};
private void loadImageSimpleTargetApplicationContext() {
Glide
.with( context.getApplicationContext() ) // safer!
.load( eatFoodyImages[1] )
.asBitmap()
.into( target2 );
}
和“普通”target唯一不同的是這個以像素為單位的圖片大小聲明:new SimpleTarget<Bitmap>( 250, 250 )
。目前已經介紹了所有關于SimpleTarget的知識點。
ViewTarget
有很多原因導致我們不能直接使用ImageView。前面已經介紹了如何獲取Bitmap?,F在,我們將更深入學習。假設你有個自定義的View。由于沒有已知的方法在哪里設置圖片,Glide并不支持加載圖片到定制的View內。然而用ViewTarget會讓這個更簡單。
讓我們看一個簡單的定制View,它繼承于FrameLayout,內部使用了一個ImageView,并上面覆蓋了一個TextView:
public class FutureStudioView extends FrameLayout {
ImageView iv;
TextView tv;
public void initialize(Context context) {
inflate( context, R.layout.custom_view_futurestudio, this );
iv = (ImageView) findViewById( R.id.custom_view_image );
tv = (TextView) findViewById( R.id.custom_view_text );
}
public FutureStudioView(Context context, AttributeSet attrs) {
super( context, attrs );
initialize( context );
}
public FutureStudioView(Context context, AttributeSet attrs, int defStyleAttr) {
super( context, attrs, defStyleAttr );
initialize( context );
}
public void setImage(Drawable drawable) {
iv = (ImageView) findViewById( R.id.custom_view_image );
iv.setImageDrawable( drawable );
}
}
由于我們定制的view并不是繼承自ImageView,這里不能使用常規的.into()方法。因此,我們只能創建一個ViewTarget,用來傳遞給.into()方法:
private void loadImageViewTarget() {
FutureStudioView customView = (FutureStudioView) findViewById( R.id.custom_view );
viewTarget = new ViewTarget<FutureStudioView, GlideDrawable>( customView ) {
@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
this.view.setImage( resource.getCurrent() );
}
};
Glide
.with( context.getApplicationContext() ) // safer!
.load( eatFoodyImages[2] )
.into( viewTarget );
}
在target的回調方法中,我們在定制view上使用我們創建的setImage(Drawable drawable)
方法設置圖片。同時,確保你注意到我們已經在ViewTarget的構造方法里傳遞了我們的定制view:new ViewTarget<FutureStudioView, GlideDrawable>( customView )
。
這應該覆蓋了所有你可能需要定制的view。你也可以在回調中做額外的工作。例如,我們可以解析即將到來的圖片的主色調,然后設置TextView的顏色。但我們相信你肯定已經有你自己的想法。
展望
在這篇較長的文章中,你已經學會了Glide中target的基礎。你已經學會了從圖片獲取Bitmap,并加載到你定制的view中??梢栽谠u論中告訴我們我們忽略了什么。
后面的文章,我們將要繼續通過例子介紹target如何向通知欄和桌面小控件加載圖片。