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

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

學習/參考地址:
https://blog.csdn.net/column/details/15318.html
https://blog.csdn.net/u013005791/article/details/74532091
http://www.lxweimin.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結束

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,412評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,514評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,373評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,975評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,743評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,199評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,262評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,414評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,951評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,780評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,527評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,218評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,649評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,889評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,673評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容