安卓基礎開發庫,讓開發簡單點。
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根據圖片資源智能地選擇使用哪一種緩存策略(默認選項)。
另外再補充兩點:
- 網絡圖片緩存是根據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。
要求:
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結束