Glide 知識梳理(2) 自定義Target

1、概述

首先,咱們回顧一下Glide的基本用法,咱們的最後一步都是調用into(ImageView imageView),經過斷點,咱們能夠看到正是這一步觸發了圖片的請求: android

這個 ImageView最終會經過 buildTarget方法,封裝在 GlideDrawableImageViewTarget當中,而後調用 GenericRequestBuilder#into方法發起請求, Glide一直跟蹤這個 Target,並在得到圖片資源以後,通知 Target來更新它內部持有的 ImageView的引用。 這個過程就好像是咱們平時請求網絡時,會傳入一個 Callback,等到異步的操做執行完畢後,經過 Callback傳回請求的資源來更新 UI。 經過源碼,能夠看到和 Target相關的類有:

  • Target
  • BaseTarget
    • SimpleTargetAppWidgetTargetPreloadTatgetNotificationTarget
    • ViewTarget
      • ImageViewTargetGlideDrawableImageViewTargetBitmapImageViewTargetDrawableImageViewTarget

今天這篇文章,咱們就來學習一下SimpleTargetViewTarget的用法,主要參考了下面連接中的文章:緩存

https://futurestud.io/tutorials/glide-callbacks-simpletarget-and-viewtarget-for-custom-view-classesbash

2、SimpleTarget

SimpleTarget能夠看做是請求的回調,咱們在回調當中進行處理,而不是傳入ImageViewGlide去負責更新。服務器

2.1 基本用法

先看一下SimpleTarget的用法:網絡

public void loadSimpleTarget(View view) {
        MySimpleTarget mySimpleTarget = new MySimpleTarget();
        Glide.with(this)
                .load(R.drawable.book_url)
                .into(mySimpleTarget);
    }

    private class MySimpleTarget extends SimpleTarget<GlideDrawable> {
        
        @Override
        public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
            mImageView.setImageDrawable(resource.getCurrent());
        }
    }
複製代碼

咱們首先定義了一個SimpleTarget,而後把它經過into方法傳入。這樣當Glide去服務器請求圖片成功以後,它會把請求到的圖片資源做爲GlideDrawable傳遞回來,你可使用這個GlideDrawable.getCurrent()進行本身想要的操做。 關於上面SimpleTarget的使用須要知道兩點:app

  • 因爲咱們把SimpleTarget定義成了局部變量,那麼它頗有可能會被回收,一旦它被回收,那麼咱們收不到任何的回調了。
  • 咱們在with中傳入了ActivityContext,那麼Glide就會監聽Activity生命週期的變化,當Activity退到後臺以後,中止該請求。若是你但願它獨立於Activity的生命週期,那麼須要傳入一個ApplicationContext

2.2 設置資源的大小

當咱們傳入ImageView時,Glide會根據ImageView的大小來自動調整緩存的圖片資源大小,而當咱們使用Target的時候,並無提供這個條件來給Glide,所以,爲了縮短處理時間和減小內存,咱們能夠按下面的方法來指定緩存的大小:異步

public void loadSimpleTarget(View view) {
        MySimpleTarget mySimpleTarget = new MySimpleTarget(50, 50);
        Glide.with(this)
                .load(R.drawable.book_url)
                .into(mySimpleTarget);
    }

    private class MySimpleTarget extends SimpleTarget<GlideDrawable> {

        public MySimpleTarget(int width, int height) {
            super(width, height);
        }

        @Override
        public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
            mImageView.setImageDrawable(resource.getCurrent());
        }
    }
複製代碼

3、ViewTarget

在上面一節中,咱們展現瞭如何經過設置回調來得到最終的Bitmap,可是上面的方法就是有一個缺陷:回調中只能拿到最終請求到的資源。咱們須要持有View的全局對象,這樣才能在收到回調以後更新它,而且,Glide沒法根據View的實際寬高來決定緩存圖片的大小。 ViewTarget就提供了這樣一種方案:咱們在構造Target時就傳入自定義的View,這樣在回調時就能夠經過它來更新UI。 它的原理其實和咱們開頭說到的傳入ImageView的原理相似,就是經過傳入Target的方式,可是ViewTarget會持有須要更新的View實例,這樣在回調時候,咱們就能執行本身須要的操做了,下面是使用ViewTarget的例子: 首先,定義一個自定義的Viewide

public class CustomView extends LinearLayout {

    private ImageView mImageView;
    private TextView mTextView;

    public CustomView(Context context) {
        super(context);
    }
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        init();
    }

    private void init() {
        mTextView = (TextView) findViewById(R.id.tv_custom_result);
        mImageView = (ImageView) findViewById(R.id.iv_custom_result);
    }

    public void setResult(Drawable drawable) {
        mTextView.setText("load success");
        mImageView.setImageDrawable(drawable);
    }
}
複製代碼

在佈局當中這麼定義它:函數

<com.example.lizejun.repoglidelearn.CustomView
        android:id="@+id/cv_result"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tv_custom_result"
            android:layout_width="match_parent"
            android:layout_height="30dp"
            style="@style/style_tv_normal"/>
        <ImageView
            android:id="@+id/iv_custom_result"
            android:layout_width="200dp"
            android:layout_height="200dp" />
    </com.example.lizejun.repoglidelearn.CustomView>
複製代碼

以後,咱們定義一個ViewTarget,並加載它:佈局

public void loadViewTarget(View view) {
        CustomView customView = (CustomView) findViewById(R.id.cv_result);
        MyViewTarget myViewTarget = new MyViewTarget(customView);
        Glide.with(this)
                .load(R.drawable.book_url)
                .into(myViewTarget);
    }

    private class MyViewTarget extends ViewTarget<CustomView, GlideDrawable> {

        public MyViewTarget(CustomView customView) {
            super(customView);
        }

        @Override
        public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
            view.setResult(resource.getCurrent());
        }
    }
複製代碼

它的整個步驟爲:

  • 首先得到這個自定義View實例。
  • 以後把這個自定義View做爲ViewTarget的構造函數的參數,新建一個ViewTarget實例。
  • 把這個ViewTarget經過into()方法傳給Glide
  • 等待Glide請求完畢,那麼會回調ViewTarget中的onResourceReady方法,該Target中有咱們傳入的自定義View,這樣,咱們就能夠調用這個自定義View內部的方法。

4、小結

  • 從繼承樹上來看,SimpleTargetViewTarget是層次最低的可實現類,也是咱們平時開發中比較經常使用的類。
  • 這二者的區別就是ViewTarget內部的實現更加複雜,它會持有View的引用,並經過內部的SizeDeterminer計算View的寬高來提供給Glide做爲參考,SimpleTarget則不會去處理這些邏輯,咱們須要手動的指定一個寬高,因此,咱們須要根據不一樣的使用場景來決定繼承於哪一個Target來實現本身的業務邏輯。
  • 除了SimpleTargetViewTargetGlide還提供了繼承於它們的Target來簡化咱們的操做。例如,更新通知欄和桌面插件,從源碼來看,它們是繼承於SimpleTarget,其最基本的原理和咱們自定義SimpleTarget都是相同的,只是在回調裏面調用AppWidgetManager/NotificationManager增長了更新相應組件的操做。在這裏就很少介紹了,有須要瞭解的能夠看下面這篇文章:

https://futurestud.io/tutorials/glide-loading-images-into-notifications-and-appwidgets

相關文章
相關標籤/搜索