1. 程式人生 > >Android 圖片庫之Glide框架之V3版本和V4版本區別

Android 圖片庫之Glide框架之V3版本和V4版本區別

關於Glide升級問題

官網連結:http://bumptech.github.io/glide/doc/migrating.html

詳細介紹如下

AndroidStudio配置

 implementation 'com.github.bumptech.glide:glide:4.7.1'

1.基礎顯示圖片

 imageview=findViewById(R.id.activity_main_imageview);
 String url = "XXX";
 Glide.with(this)
       .load(url)
       .into(imageview);

和V3沒有任何區別,不做過多贅述。

2.載入幾種不同路徑下的圖片

imageview=findViewById(R.id.activity_listview_imageview);
 
/**
  * 載入本地圖片 比如sd卡中的圖片
* */
 
File file = new File(Environment.getExternalStorageDirectory() + "/icon.png");
Glide.with(this)
      .load(file)
      .into(imageview);
 
 
/**
  * 載入應用資源 比如mipmap下的圖片
* */
 
int resource = R.mipmap.za;
Glide.with(this)
      .load(resource)
      .into(imageview);
 
/**
 * 載入二進位制流 比如從伺服器獲取的圖片流
* */
        
byte[] image =XXX;
Glide.with(this)
     .load(image)
     .into(imageview);
 
        
/**
 * 載入Uri物件 比如獲取的相機相簿圖片
 * */
        
Uri imageUri =XXX;
Glide.with(this)
      .load(imageUri)
      .into(imageview);

和V3沒有任何區別,不做過多贅述。

3.新增佔位符

 imageview=findViewById(R.id.activity_main_imageview);
        String url = "XXX";
        RequestOptions options = new RequestOptions()
                .placeholder(R.mipmap.ic_launcher_round)
                .error(R.mipmap.ic_launcher_round);
        Glide.with(this)
                .load(url)
                .apply(options)
                .into(imageview);
如上,V4版本需要建立RequestOptions物件。然後通過RequestOptions物件來設定placeholder(載入成功前)以及error(載入失敗)佔位符。

4.縮圖

imageview=findViewById(R.id.activity_main_imageview);
String url = "XXX";
Glide.with(this)
     .load(url)
     .thumbnail(0.5f)
      .into(imageview);

和V3沒有任何區別,不做過多贅述。

5.圖片大小與裁剪

實際上,使用Glide在大多數情況下我們都是不需要指定圖片大小的,因為Glide會自動根據ImageView的大小來決定圖片的大小,以此保證圖片不會佔用過多的記憶體從而引發OOM。但是,如果你真的有這樣的需求,必須給圖片指定一個固定的大小,Glide仍然是支援這個功能的。

imageview=findViewById(R.id.activity_main_imageview);
String url = "XXX";
RequestOptions options = new RequestOptions()
   .override(200, 200);
Glide.with(this)
      .load(url)
      .apply(options)
      .into(imageview);

如上,V4版本需要建立RequestOptions物件。然後通過RequestOptions物件來設定override即圖片的大小。

如果你想載入一張圖片的原始尺寸的話,可以使用Target.SIZE_ORIGINAL關鍵字。

imageview=findViewById(R.id.activity_main_imageview);
String url = "XXX";
RequestOptions options = new RequestOptions()
       .override(Target.SIZE_ORIGINAL);
Glide.with(this)
     .load(url)
     .apply(options)
     .into(imageview);

這樣的話,Glide就不會再去自動壓縮圖片,而是會去載入圖片的原始尺寸。當然,這種寫法也會面臨著更高的OOM風險。

6.圖片的快取

6.1.禁用記憶體快取(不操作即預設開啟)

 imageview=findViewById(R.id.activity_main_imageview);
 String url = "XXX";
 RequestOptions options = new RequestOptions()
        .skipMemoryCache(true);
 Glide.with(this)
      .load(url)
      .apply(options)
      .into(imageview);

如上,V4版本需要建立RequestOptions物件。然後通過RequestOptions物件來設定skipMemoryCache,傳入true表示禁止記憶體快取該圖片。預設未開啟,不設定即可。

6.2.禁用硬碟快取(不操作即預設開啟)

imageview=findViewById(R.id.activity_main_imageview);
String url = "XXX";
RequestOptions options = new RequestOptions()
      .diskCacheStrategy(DiskCacheStrategy.NONE);
Glide.with(this)
     .load(url)
     .apply(options)
     .into(imageview);

如上,V4版本需要建立RequestOptions物件。然後通過RequestOptions物件來設定diskCacheStrategy。傳值及意義如下:

DiskCacheStrategy.NONE: 表示不快取任何內容。

DiskCacheStrategy.DATA: 表示只快取原始圖片。

DiskCacheStrategy.RESOURCE: 表示只快取轉換過後的圖片。

DiskCacheStrategy.ALL : 表示既快取原始圖片,也快取轉換過後的圖片。

DiskCacheStrategy.AUTOMATIC: 表示讓Glide根據圖片資源智慧地選擇使用哪一種快取策略(預設選項)。

DiskCacheStrategy.DATA   對應V3中的   DiskCacheStrategy.SOURCE

DiskCacheStrategy.RESOURCE   對應V3的   DiskCacheStrategy.RESULT

DiskCacheStrategy.AUTOMATIC是Glide 4中新增的一種快取策略,並且在不指定diskCacheStrategy的情況下預設使用就是的這種快取策略。

7.顯示Gif和Video

顯示GIF方式1:asGif()方法

imageview=findViewById(R.id.activity_main_imageview);
String url = "XXX";
Glide.with(this)
     .asGif()
     .load(url)
     .into(imageview);

用asGif()方法,如果url對應的圖片不是gif型別,則直接顯示.error(R.mipmap.za)設定的圖片。如果是gif型別的圖片則直接顯示。

顯示GIF方式2:asBitmap()方法

imageview=findViewById(R.id.activity_main_imageview);
String url = "http://guolin.tech/test.gif";
Glide.with(this)
      .asBitmap()
      .load(url)
      .into(imageview);
用asBitmap()方法,如果url對應的圖片不是gif型別,直接顯示圖片。如果是gif型別的圖片,則顯示Gif的第一幀圖片。

所以因為圖片的格式可能不確定(有時是動圖,有時是靜圖)所以最好兩個都不加,Glide框架會自行判斷

注意:

1.相比V3版本,V4版本asGif()方法和asBitmap()方法要在load(url)方法之前新增。

2.相比V3版本,V4版本還添加了幾個as方法。也要在load(url)方法之前新增。


顯示Video(目前只支援本地)

imageview=findViewById(R.id.activity_main_imageview);
String url = Environment.getExternalStorageDirectory()+"/123.mp4";
Glide.with(this)
     .load(Uri.fromFile(new File(url)))
     .into(imageview);

顯示本地視訊的封面。

8.各種Target


Glide的所有Target

舉例說明

1.SimpleTarget

泛型為Drawable:

1.此時必須刪除.asBitmap()方法。

2.在onResourceReady回撥方法中獲取的是Drawable 所以imageview.setBackground(resource);

public void initView(){
        imageview=findViewById(R.id.activity_main_imageview);
        String url ="XXX";
        Glide.with(this)
                .load(url)
                .into(mSimpleTarget);
    }

    private SimpleTarget<Drawable> mSimpleTarget = new SimpleTarget<Drawable>() {
        @Override
        public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
            imageview.setBackground(resource);
        }
    };

泛型為Bitmap:

1.此時必須使用.asBitmap()方法。

2.在onResourceReady回撥方法中獲取的是Bitmap 所以 imageview.setImageBitmap(resource);

public void initView(){
        imageview=findViewById(R.id.activity_main_imageview);
        String url ="XXX";
        Glide.with(this)
                .asBitmap()
                .load(url)
                .into(mSimpleTarget);
    }

    private SimpleTarget<Bitmap> mSimpleTarget = new SimpleTarget<Bitmap>() {
        @Override
        public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
            imageview.setImageBitmap(resource);
        }
    };

利用SimpleTarget類改變圖片大小 替換上面實現類

private SimpleTarget<Bitmap> mSimpleTarget = new SimpleTarget<Bitmap>(200,200) {
        @Override
        public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
            imageview.setImageBitmap(resource);
        }
    };
即顯示的時候只需要是 200x200 的尺寸來節省時間和記憶體,你可以在 SimpleTarget 的回撥宣告中指定圖片的大小。

從程式碼中可以看到 SimpleTarget 的物件的宣告沒有使用匿名物件,而是單獨的聲明瞭一個變數,這裡是故意這麼做的,如果使用匿名內部類的方式建立 SimpleTarget 的物件,這樣會增大該物件在 Glide 完成圖片請求之前就被回收的可能性。

上面Glide的with() 方法傳入 Activity 或者 Fragment 時 Glide 的圖片載入會與他們的生命週期關聯起來,但是如果我們使用 Target 的話,這個 Target 就有可能獨立於他們的生命週期以外,這時候我們就需要使用 context.getApplicationContext() 的上下文了,這樣只有在應用完全停止時 Glide 才會殺死這個圖片請求。

2.ViewTarget

ViewTarget的功能更加廣泛,它可以作用在任意的View上。

自定義View

public class MyLayout extends RelativeLayout{

    private ViewTarget<MyLayout, Drawable> viewTarget;

    public MyLayout(Context context) {
        super(context);
        initviewTarget();
    }

    public MyLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initviewTarget();
    }

    public void initviewTarget(){
        viewTarget = new ViewTarget<MyLayout, Drawable>(this) {

            @Override
            public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
                MyLayout myLayout = getView();
                myLayout.setBackground(resource);
            }
        };
    }

    /**
     * 外界使用提供獲取ViewTarget物件的方法
     * */

    public ViewTarget<MyLayout, Drawable> getTarget() {
        return viewTarget;
    }

}

佈局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.wjn.glidedemo.view.MyLayout
        android:id="@+id/activity_main_fatherlayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:id="@+id/activity_main_imageview"
            android:layout_width="300dp"
            android:layout_height="300dp" />

    </com.wjn.glidedemo.view.MyLayout>

</LinearLayout>

呼叫

public class MainActivity extends AppCompatActivity {

    private MyLayout fatherlayout;
    private ImageView imageview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    public void initView() {
        fatherlayout=findViewById(R.id.activity_main_fatherlayout);
        String fatherurl = "XXX";
        Glide.with(this)
                .load(fatherurl)
                .into(fatherlayout.getTarget());

        imageview = findViewById(R.id.activity_main_imageview);
        String url = "XXX";
        Glide.with(this)
                .asBitmap()
                .load(url)
                .into(mSimpleTarget);
    }

    private SimpleTarget<Bitmap> mSimpleTarget = new SimpleTarget<Bitmap>(200, 200) {
        @Override
        public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
            imageview.setImageBitmap(resource);
        }
    };

}

總結:

1.一般我們都是在ImageView上顯示圖片,所以大部分情況下使用第一種SimpleTarget即可滿足條件。

2.如果要在其他View上顯示圖片,比如RelativeLayout LinearLayout等等,此時可以使用ViewTarget。

3.SimpleTarget的泛型一般為Drawable或Bitmap。ViewTarget的第二個引數也是如此。

4.V3版本泛型為GlideDrawable,而V4版本泛型為Drawable。

9.載入圓形圖片

方式1:自定義BitmapTransformation類 然後使用transform方法。

BitmapTransformation實現類

public class GlideCircleTransform extends BitmapTransformation {

    public GlideCircleTransform() {
        super();
    }

    @Override
    public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {

    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        return circleCrop(pool, toTransform);
    }

    private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

        int size = Math.min(source.getWidth(), source.getHeight());
        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;

        // TODO this could be acquired from the pool too
        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);

        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        float r = size / 2f;
        canvas.drawCircle(r, r, r, paint);
        return result;
    }

}

使用

imageview = findViewById(R.id.activity_main_imageview);
String url="XXX";
RequestOptions options = new RequestOptions()
       .transform(new GlideCircleTransform());
Glide.with(this)
     .load(url)
     .apply(options)
     .into(imageview);

方式2:直接使用RequestOptions物件的circleCrop方法。

 imageview = findViewById(R.id.activity_main_imageview);
 String url = "XXX";
 RequestOptions options = new RequestOptions()
        .circleCrop();
 Glide.with(this)
      .load(url)
      .apply(options)
      .into(imageview);
即使用RequestOptions物件的circleCrop方法即可。

10.載入圓角圖片

BitmapTransformation實現類

public class GlideRoundTransform extends BitmapTransformation {

    private float radius;

    public GlideRoundTransform(int dp) {
        super();
        this.radius = Resources.getSystem().getDisplayMetrics().density * dp;
    }

    @Override
    public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {

    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        return roundCrop(pool, toTransform);
    }

    private Bitmap roundCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

        Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
        canvas.drawRoundRect(rectF, radius, radius, paint);
        return result;
    }
    
}

使用

  imageview = findViewById(R.id.activity_main_imageview);
  String url="http://guolin.tech/test.gif";
  RequestOptions options = new RequestOptions()
       .transform(new GlideRoundTransform(20));
  Glide.with(this)
       .load(url)
       .apply(options)
       .into(imageview);

另外還有幾個常見的方法CenterCrop、FitCenter。

RequestOptions options = new RequestOptions()
        .centerCrop();

RequestOptions options = new RequestOptions()
        .fitCenter();

11.更改Glide配置項

建立AppGlideModule實現類

@GlideModule
public class MyAppGlideModule extends AppGlideModule {

    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
    }

    @Override
    public void registerComponents(Context context, Glide glide, Registry registry) {

    }

}

applyOptions方法:更改Glide配置。

registerComponents方法:替換Glide元件。

MyAppGlideModule類在上面,我們加入了一個@GlideModule的註解,這是V4和V3最大的一個不同之處。在V3中,我們定義了自定義模組之後,還必須在AndroidManifest.xml檔案中去註冊它才能生效,而在Glide 4中是不需要的,因為@GlideModule這個註解已經能夠讓Glide識別到這個自定義模組了。

12.GlideApp使用

1.首先AndroidStudio新增配置

implementation 'com.github.bumptech.glide:glide:4.7.1'
implementation 'com.android.support:support-v4:27.1.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.4.0'

2.建立AppGlideModule實現類,並新增@GlideModule

@GlideModule
public class MyAppGlideModule extends AppGlideModule {

    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
    }

    @Override
    public void registerComponents(Context context, Glide glide, Registry registry) {

    }

}

3.clean rebuild make project 後找到GlideApp類(自動生成)

4.使用

GlideApp.with(this)
        .load(url)
        .placeholder(R.mipmap.ic_launcher)
        .error(R.mipmap.ic_launcher)
        .skipMemoryCache(true)
        .diskCacheStrategy(DiskCacheStrategy.NONE)
        .override(Target.SIZE_ORIGINAL)
        .circleCrop()
        .into(imageview);