安卓基礎開發庫,讓開發簡單點。
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根據圖片資源智慧地選擇使用哪一種快取策略(預設選項)。
另外再補充兩點:
- 網路圖片快取是根據url地址進行儲存的,對於同一張圖片但其url地址不同(可變動)的情況,則無法起到快取作用。這個時候可以通過自定義Url來應對這種情況,具體方案請參考這裡的“高階技巧”小節。
- 清空快取資料
//清空記憶體快取,要求在主執行緒中執行
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。
要求:
- 類上方加入@GlideExtension註解。
- 自定義的方法上方加入@GlideOption註解。
- 自定義的方法須為靜態方法,且第一個引數必須是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結束
複製程式碼