Glide 入門到精通之九——SimpleTarget 和 ViewTarget 用於自定義視圖類


http://mrfu.me/2016/02/27/Glide_Thumbnails/

Glide 中的回調:Targets

目前爲止,我們很方便的使用 Glide 建造者去加載圖片到 ImageView 中了。Glide 隱藏了一大堆複雜的在後臺的場景。Glide 做了所有的網絡請求和處理在後臺線程中,一旦結果準備好了之後,切回到 UI 線程然後更新 ImageView。

在這篇博客中,我們假定 ImageView 不再是圖像的最後一步。我們只要 Bitmap 本身。Glide 提供了一個用 Targets 的簡單的方式去接受圖片資源的 Bitmap。Targets 是回調函數,它在 Glide 做完所有的加載和處理之後返回結果。

Glide 提供了各種的 targets 並且每個都有其明確的目的。我們將在接下來的幾節中通過使用它們。讓我們從 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 );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

這段代碼的第一部分創建了一個字段對象,聲明瞭一個方法,即一旦 Glide 已加載並處理完圖像,它將被調用。這個回調方法傳了 Bitmap 作爲一個參數。你之後便可以使用這個 Bitmap 對象,無論你要怎樣用它。

這段代碼的第二部分是我們如何通過 Glide 用 targets:和 ImageView 用法完全相同的!你既可以傳一個 Target 也可以傳一個ImageView 參數給.into() 方法。Glide 自己將會處理並返回結果給任何一個。這裏有一些不同的是,我們添加了.asBitmap(),它強制 Glide 去返回一個 Bitmap 對象。記住,Glide 也可以加載 Gif 或 video 的。爲了防止 target 的衝突(我們需要 Bitmap) 和未知資源在網絡背後的 URL(可能是一個 Gif),我們可以調用 .asBitmap() 告訴 Glide 我們需要一個圖像。

關注 Targets

除了知道如何實現一個簡單版本的 Glide 的 Target 回調系統,你要學會額外兩件事。

  • 首先是 SimpleTarget 對象的字段聲明。從技術上來說,Java/Android 會允許你在 .into() 方法中去聲明 target 的匿名內部類。然而,這大大增加了這樣一個可能性:即在 Glide 做完圖片請求之前, Android 垃圾回收移除了這個匿名內部類對象。最終這可能會導致一個情況,當圖像加載完成了,但是回調再也不會被調用。所請確保你所聲明的回調對象是作爲一個字段對象的,這樣你就可以保護它避免被邪惡的 Android 垃圾回收機制回收 ;

  • 第二個關鍵部分是 Glide 建造者中這行:.with(context)。 這裏的問題實際是 Glide 的功能:當你傳了一個 context(例如是當前應用的 activity),Glide 將會自動停止請求當 activity 已經停止的時候。這整合到了應用的生命週期中通常是非常有幫助的,但是有時工作起來是困難的,如果你的 target 是獨立於應用的 activity 生命週期。這裏的解決方案是用 application 的 context: .with(context.getApplicationContext))。當應用資深完全停止時,Glide 纔會殺死這個圖片請求。請求記住,再說一次,如果你的請求需要在 activity 生命週期之外去做時,才用下面這樣的代碼:

private void loadImageSimpleTargetApplicationContext() {  
    Glide
        .with( context.getApplicationContext() ) // safer!
        .load( eatFoodyImages[1] 
        .asBitmap()
        .into( target2 );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Target 指定尺寸

另一個潛在的問題是,target 沒有指明大小。如果你傳一個 ImageView 作爲參數給 .into(),Glide 將會用 ImageView 的大小去限制圖像的大小。比如說,如果加載的圖片是 1000x1000 像素的,但是 ImageView 只有 250x250 像素,Glide 將會減少圖片的尺寸去節省時間和內存。很顯然,在和 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 );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

ViewTarget

我們不能直接使用 ImageView 的原因可能是多種多樣的。我們已經向你展示如何去接收一個 Bitmap。現在我們要更進一步。假設你有一個 Custom View。Glide 並不支持加載圖片到自定義 view 中,因爲並沒有方法知道圖片應該在哪裏被設置。然而,Glide 可以用 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 );
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

你不能使用常規的 Glide 的方法 .into(),因爲我們的自定義 view 並不繼承自 ImageView。因此,我們必須創建一個 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 );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在 target 回調方法中,我們使用我們創建的方法 setImage(Drawable drawable) 在自定義 view 類中去設置圖片。另外確保你注意到我們必須在ViewTarget 的構造函數中傳遞我們自定義 view 作爲參數:new ViewTarget<FutureStudioView, GlideDrawable>(customView)

這應該涵蓋了所有你需要的自定義 view。你也可以在回調中添加額外的工作。如,我們可以分析傳入的 Bitmap 的主要的顏色並設置十六進制值給 TextView。但我們相信你應該已經有一些想法了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章