讓你快速上手的Glide4.x教程

JYcoder發表於2018-03-31

安卓基礎開發庫,讓開發簡單點。
DevRing & Demo地址github.com/LJYcoder/De…

學習/參考地址:
https://blog.csdn.net/column/details/15318.html
https://blog.csdn.net/u013005791/article/details/74532091
https://www.jianshu.com/p/325bd2f56ca7

前言

距離上次發新篇已經有五個月了,趁現在無業遊民一個,趕緊寫多幾篇完善一下這個系列。
今天給大家帶來的是圖片載入框架Glide的使用介紹。這裡首推郭神的Glide系列教程,配合了原始碼講解得很詳細清晰。下面算是對學習實踐後做的一個歸納總結,不涉及原始碼分析,僅涉及相關用法。
Glide相比起Fresco要輕量很多,api呼叫起來也很簡潔,對圖片載入要求不是很高的話建議使用Glide。 關於Fresco與Glide的對比可以參考這裡

本文介紹涉及的Glide版本為4.x

介紹

下面還是和以前一樣,分幾個模組來進行介紹:配置、載入圖片、獲取Bitmap、下載圖片、Generated API、混淆。

1. 配置

1.1 新增依賴

compile 'com.github.bumptech.glide:glide:4.4.0' 
annotationProcessor 'com.github.bumptech.glide:compiler:4.4.0' //註解處理器
複製程式碼

1.2 自定義模組

自定義模組包括:修改預設配置 和 替換元件。
實現方式是通過繼承AppGlideModule類並重寫相關方法實現的。記得在該類上方加上@GlideModule註解以便Glide識別。如下:

@GlideModule
public class GlideConfigModule extends AppGlideModule {

    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
          //修改預設配置,如快取配置
    }

    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
          //替換元件,如網路請求元件
    }

}
複製程式碼

1.2.1 快取

在applyOption中對磁碟快取和記憶體快取進行相關配置

@Override
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
    //磁碟快取配置(預設快取大小250M,預設儲存在內部儲存中)
    //設定磁碟快取儲存在外部儲存,且指定快取大小
    builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, diskCacheSize);
    //設定磁碟快取儲存在自己指定的目錄下,且指定快取大小
    builder.setDiskCache(new DiskLruCacheFactory(new DiskLruCacheFactory.CacheDirectoryGetter() {
        @Override
        public File getCacheDirectory() {
            return diskCacheFolder;
        }
    }, diskCacheSize);

    //記憶體快取配置(不建議配置,Glide會自動根據手機配置進行分配)
    //設定記憶體快取大小
    builder.setMemoryCache(new LruResourceCache(memoryCacheSize));
    //設定Bitmap池大小
    builder.setBitmapPool(new LruBitmapPool(bitmapPoolSize));
}
複製程式碼

1.2.2 替換元件

比如替換網路元件為okhttp。
新增相關依賴即可。

compile 'com.squareup.okhttp3:okhttp:3.9.0'
compile 'com.github.bumptech.glide:okhttp3-integration:4.3.1'
複製程式碼

它內部實現其實就是在registerComponents中進行了元件替換.

@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
     registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
}
複製程式碼

當然還有很多元件可以替換,但一般沒這種需求。

//Glide中預設元件
register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
register(File.class, InputStream.class, new StreamFileLoader.Factory());
register(int.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
register(int.class, InputStream.class, new StreamResourceLoader.Factory());
register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
register(Integer.class, InputStream.class, new StreamResourceLoader.Factory());
register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory());
register(String.class, InputStream.class, new StreamStringLoader.Factory());
register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory());
register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
register(URL.class, InputStream.class, new StreamUrlLoader.Factory());
register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory());
...
複製程式碼

1.2.3 注意

一個專案(包含主專案與依賴庫)中只能存在一個繼承AppGlideModule的自定義模組,如果有多個,則會報com.android.dex.DexException: Multiple dex files define Lcom/bumptech/glide/GeneratedAppGlideModuleImpl異常。
但是允許有多個繼承LibraryGlideModule的自定義模組(用於重寫registerComponents進行元件替換)。

2. 載入圖片

2.1 常用操作

2.1.1 載入圖片到ImageView

Glide.with(context)
        .load(url)
        .into(imageView);
複製程式碼

其中,
with()方法的引數可以是Activity、Fragment等。將用於圖片載入的生命週期,比如傳入的是activity,那麼在activity銷燬時將對相關圖片資源進行回收。
load()方法的引數可以為String、Uri、File、資源ID等。
into()方法的引數可以是ImageView,Target、圖片的寬高。

2.1.2 載入圖片到ImageView,並指定佔點陣圖

RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(loadingResId) //設定“載入中”狀態時顯示的圖片
              .error(errorResId); //設定“載入失敗”狀態時顯示的圖片
Glide.with(context)
     .load(url)
     .apply(requestOptions)
     .into(imageView);
複製程式碼

2.1.3 載入圖片到ImageView,並指定快取策略

RequestOptions requestOptions = new RequestOptions();
requestOptions.skipMemoryCache(true) //不加入記憶體快取,預設會加入
              .diskCacheStrategy(DiskCacheStrategy.NONE); //不加入磁碟快取
Glide.with(context)
     .load(url)
     .apply(requestOptions)
     .into(imageView);
複製程式碼

磁碟快取策略有以下幾種:
DiskCacheStrategy.NONE: 表示不快取任何內容。
DiskCacheStrategy.DATA: 表示只快取原始圖片。
DiskCacheStrategy.RESOURCE: 表示只快取轉換過後的圖片。
DiskCacheStrategy.ALL : 表示既快取原始圖片,也快取轉換過後的圖片。
DiskCacheStrategy.AUTOMATIC: 表示讓Glide根據圖片資源智慧地選擇使用哪一種快取策略(預設選項)。

另外再補充兩點:

  1. 網路圖片快取是根據url地址進行儲存的,對於同一張圖片但其url地址不同(可變動)的情況,則無法起到快取作用。這個時候可以通過自定義Url來應對這種情況,具體方案請參考這裡的“高階技巧”小節。
  2. 清空快取資料
//清空記憶體快取,要求在主執行緒中執行
Glide.get(mContext).clearMemory();

//清空磁碟快取,要求在後臺執行緒中執行
Glide.get(mContext).clearDiskCache();
複製程式碼

####2.1.4 載入圖片到ImageView,並指定圖片大小

RequestOptions requestOptions = new RequestOptions();
requestOptions.override(300, 200); //指定大小為300*200,無視imageView大小
//requestOptions.override(Target.SIZE_ORIGINAL); //指定大小為圖片原始大小,有更高OOM風險
Glide.with(context)
     .load(url)
     .apply(requestOptions)
     .into(imageView);
複製程式碼

2.1.5 載入圖片到ImageView,並配置過渡動畫

Glide.with(context)
     .load(url)
     .transition(DrawableTransitionOptions.withCrossFade(600))//適用於Drawable,過渡動畫持續600ms
//     .transition(BitmapTransitionOptions.withCrossFade(600))//適用於Bitmap,過渡動畫持續600ms
//     .transition(GenericTransitionOptions.with(animationId))//適用於自定義過渡效果,傳入animationId      
     .into(imageView);
複製程式碼

2.1.6 載入圖片到ImageView,並加入圖片變換

確保已新增圖片變換庫依賴:

 compile 'jp.wasabeef:glide-transformations:3.1.1@aar'//圖片轉換工具
複製程式碼

應用單個變換

RequestOptions requestOptions = new RequestOptions();
//加入圓角變換
requestOptions.transform(new RoundedCornersTransformation(radius, margin));
//加入模糊變換
//requestOptions.transform(new BlurTransformation(blurRadius));
//加入灰白變換
//requestOptions.transform(new GrayscaleTransformation());
....
Glide.with(context)
     .load(url)
     .apply(requestOptions)
     .into(imageView);
複製程式碼

同時應用多個變換

List<Transformation> list = new ArrayList<>();
list.add(new RoundedCornersTransformation(radius, margin));
list.add(new BlurTransformation(blurRadius));
list.add(new GrayscaleTransformation());
MultiTransformation multiTransformation = new MultiTransformation(list);
RequestOptions requestOptions = new RequestOptions();
//同時應用圓角、模糊、灰白的變換效果
requestOptions.transform(multiTransformation);
Glide.with(context)
     .load(url)
     .apply(requestOptions)
     .into(imageView);
複製程式碼

更多變換效果請檢視https://github.com/wasabeef/glide-transformations。
另外,可以通過dontTransform()禁用圖片變換。

RequestOptions requestOptions = new RequestOptions();
requestOptions.dontTransform();
Glide.with(context)
     .load(url)
     .apply(requestOptions)
     .into(imageView);
複製程式碼

2.2 預載入

有時為了更流暢的體驗,可以使用預載入功能先把圖片準備好,等到要顯示時載入速度就很快了。

Glide.with(context)
     .load(url)
     .preload();
複製程式碼

2.3 監聽載入結果

如果你需要知道載入的結果,可以使用listener()進行監聽。

Glide.with(context)
     .load(url)
     .listener(new RequestListener<Drawable>() {
        @Override
        public boolean onLoadFailed(@Nullable GlideException e, Object model,     Target<Drawable> target, boolean isFirstResource) {
            //載入失敗
            return false;
        }

        @Override
        public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
            //載入成功,resource為載入到的圖片
            //如果return true,則不會再回撥Target的onResourceReady(也就是不再往下傳遞),imageView也就不會顯示載入到的圖片了。
            return false;
        }
     }).into(imageView);
複製程式碼

3. 獲取Bitmap

有些時候,我們需要拿到載入回來的Bitmap物件,下面介紹兩種實現方式。

3.1 通過listener()實現

Glide.with(context)
     .asBitmap() //指定格式為Bitmap
     .load(url)
     .listener(new RequestListener<Bitmap>() {
          @Override
          public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
              //載入失敗
              return false;
          }
          @Override
          public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
              //載入成功,resource為載入到的bitmap
              return false;
          }
      })
     .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);//載入原圖大小
複製程式碼

3.2 通過SimpleTarget實現

Glide.with(context)
     .asBitmap()
     .load(url)
     .into(new SimpleTarget<Bitmap>() {
          @Override
          public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
                //載入成功,resource為載入到的bitmap
          }
      });
//這種實現方式就無法監聽到載入失敗的結果
複製程式碼

4. 下載圖片

使用submit()方法實現圖片的下載。
下載圖片並儲存到指定的檔案中:

public void downLoadImage(final Context context, final String url, final File targetFile, final ImageListener<File> imageListener) {
    if (cacheThreadPool == null) {
        cacheThreadPool = Executors.newCachedThreadPool();
    }

    cacheThreadPool.execute(new Runnable() {
        @Override
        public void run() {
            try {
                File sourceFile = Glide.with(context).asFile().load(url).submit().get();
                if (FileUtil.copyFile(sourceFile, targetFile) && imageListener != null) {
                    imageListener.onSuccess(targetFile);//通過回撥傳遞File,回撥在後臺執行緒
                }
            } catch (Exception exception) {
                if (imageListener != null) {
                    imageListener.onFail(exception);//回撥在後臺執行緒
                }
            }
        }
    });
}
複製程式碼

5. Generated API

Glide4.x之後引入的新功能。

5.1 作用1:可以繼續像3.x那樣鏈式呼叫載入

前提是專案中需要有一個自定義模組(參照1.2節)
然後便可以像3.x那樣載入圖片

GlideApp.with(context)
        .load(url)
        .placeholder(R.mipmap.loading)
        .error(R.mipmap.error)
        .override(300,300)
        .transition(DrawableTransitionOptions.withCrossFade(600))
        .tranform(new GrayscaleTransformation())
        .skipMemoryCache(true)
        .diskCacheStrategy(DiskCacheStrategy.NONE)
        ....
        .into(imageView);
複製程式碼

5.2 作用2:定製屬於你的API

假設現在需要每次載入圖片都開啟過渡動畫效果,可以每次載入時加入.transition(DrawableTransitionOptions.withCrossFade(duration))來實現,但每次都寫這麼長的程式碼難免不太方便,這時可以通過定製API來實現。
自定義一個類,用於定製API。
要求:

  1. 類上方加入@GlideExtension註解。
  2. 自定義的方法上方加入@GlideOption註解。
  3. 自定義的方法須為靜態方法,且第一個引數必須是RequestOptions,後面可以加入任意多個你想自定義的引數。
@GlideExtension
public class MyGlideExtension {
    private MyGlideExtension() {
    }

    @GlideOption
    public static void useTransition(RequestOptions options) {
        options.transition(DrawableTransitionOptions.withCrossFade(600))
    }
}
複製程式碼

ReBuild專案後,便可如下呼叫:

GlideApp.with(context)
        .load(url)
        .useTransition() //使用過渡動畫效果
        .into(imageView);
複製程式碼

6. 混淆

在proguard-rules.pro檔案中新增以下內容進行混淆配置

#glide開始
-keep public class * implements com.bumptech.glide.module.AppGlideModule
-keep public class * implements com.bumptech.glide.module.LibraryGlideModule
-keep class com.bumptech.glide.** { *; }
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
    **[] $VALUES;
    public *;
}
#glide結束
複製程式碼

相關文章