概述
Glide是一個(gè)Android的圖片加載和緩存庫俱尼,它主要專注于大量圖片的流暢加載,Glide幾乎可以勝任任何你需要使用到圖片從網(wǎng)絡(luò)拉取漫玄,壓縮疫铜,顯示的場(chǎng)景。
本文主要基于Glide4.0版本介紹其基本使用方法运翼。
1 集成
Github地址:?https://github.com/bumptech/glide
app或lib級(jí)別的build.gradle文件添加依賴:
dependencies { ?compile 'com.github.bumptech.glide:glide:4.0.0-RC1' ?annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0-RC1'}在proguard.pro/proguard.cfg中添加混淆:
-keep public class * implements com.bumptech.glide.module.GlideModule-keep public class * extends com.bumptech.glide.AppGlideModule-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { ?**[] $VALUES; ?public *; } # for DexGuard only -keepresourcexmlelements manifest/application/meta-data@value=GlideModule2 基本用法
大多數(shù)情況下加載圖片只需要一行代碼:
Glide.with(fragment) ? ?.load(myUrl) ? ?.into(imageView);取消加載也很簡(jiǎn)單:
Glide.with(fragment).clear(imageView);實(shí)際上你并不需要取消加載返干。。血淌。
因?yàn)楫?dāng)你在with方法中傳入的Activity或Fragment被銷毀的時(shí)候矩欠,Glide會(huì)自動(dòng)取消加載并且回收所有的加載過程中所使用的資源。
3 注解(V4新特性)和自定義方法
Glide使用了annotation processor來生成API悠夯,允許應(yīng)用修改RequestBuilder癌淮、RequestOptions和任意的包含在單一流式API庫中的方法。這是V4的特性沦补,運(yùn)用注解后使用起來更方便:
GlideApp.with(fragment) ? .load(myUrl) ? .placeholder(R.drawable.placeholder) ? .fitCenter() ? .into(imageView);Glidev4中的Glide.with().load()后沒有之前版本的fitCenter和placeholder這樣的方法该默,但是GlideApp有,可以直接在builder中使用策彤。GlideApp可以代替之前版本的Glide開頭栓袖。
這樣做的目的是:
1.對(duì)于library項(xiàng)目來講可以使用自定義方法繼承Glide的API?
2.對(duì)于應(yīng)用來講匣摘,在繼承Glide的API后,可以通過添加自定義方法裹刮。
雖然你也可以手動(dòng)繼承RequestOptions音榜,但是顯然這樣做更加麻煩,也破壞了流式API特性捧弃。
3.1 在項(xiàng)目中實(shí)現(xiàn)AppGlideModule:
@GlideModulepublic final class CustomGlideModule extends AppGlideModule {}這個(gè)類實(shí)現(xiàn)必須要有@GlideModule注解赠叼,如果你添加的方法失效,那就檢查下這里违霞。
如果是library就實(shí)現(xiàn)LibraryGlideModule,以使用OkHttp為例:
@GlideModulepublic final class OkHttpLibraryGlideModule extends LibraryGlideModule { ?@Override ?public void registerComponents(Context context, Registry registry) { ? ?registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory()); ?} }OkHttpUrlLoader是Glide的OKHttp擴(kuò)展庫中的類,如果需要使用Glide的實(shí)現(xiàn)嘴办,可以在依賴中添加:
compile 'com.github.bumptech.glide:okhttp3-integration:4.0.0-RC1'添加完依賴不需要自己實(shí)現(xiàn)OkHttpLibraryGlideModule類,庫中已經(jīng)自帶了买鸽,會(huì)自動(dòng)使用OKHttp的涧郊。
然后編譯工程可以發(fā)現(xiàn)在build中生成了四個(gè)類:
3.2 GlideExtension
為了添加新的方法,修改已有的方法或者添加對(duì)其他類型格式的支持眼五,你需要在擴(kuò)展中使用加了注解的靜態(tài)方法妆艘。
GlideOption用來添加自定義的方法,GlideType用來支持新的格式看幼。
3.2.1 GlideOption
先新建一個(gè)CustomGlideExtension類:
@GlideExtensionpublic class CustomGlideExtension { ? ?//縮略圖的最小尺寸批旺,單位:px ? ?private static final int MINI_THUMB_SIZE = 100; ? ?/** ? ? * 將構(gòu)造方法設(shè)為私有,作為工具類使用 ? ? */ ? ?private CustomGlideExtension() { ? ?} ? ?/** ? ? * 1.自己新增的方法的第一個(gè)參數(shù)必須是RequestOptions options ? ? * 2.方法必須是靜態(tài)的 ? ? * @param options ? ? */ ? ?@GlideOption ? ?public static void miniThumb(RequestOptions options) { ? ? ? ?options ? ? ? ? ? ? ? ?.fitCenter() ? ? ? ? ? ? ? ?.override(MINI_THUMB_SIZE); ? ?} }編譯工程诵姜,打開build目錄中的GlideOptions汽煮,可以看見自動(dòng)生成了兩個(gè)方法:
public class GlideOptions extends RequestOptions { ?/** ? * @see CustomGlideExtension#miniThumb(RequestOptions) ? */ ?public GlideOptions miniThumb() { ? ?CustomGlideExtension.miniThumb(this); ? ?? ? ? ?return this; ?} ?/** ? * @see CustomGlideExtension#miniThumb(RequestOptions) ? */ ?public static GlideOptions miniThumbOf() { ? ?
? ? ? ?return new GlideOptions().miniThumb(); ?} ?... }
現(xiàn)在可以使用你自定義的方法了:
GlideApp.with(fragment).load(url).miniThumb(thumbnailSize).into(imageView);3.2.2 GlideType
以添加對(duì)GIF格式的支持為例,只是舉例,實(shí)際上API中已經(jīng)支持了棚唆。
在剛才的CustomGlideExtension類中加上:
@GlideExtensionpublic class CustomGlideExtension { ? ?private static final RequestOptions DECODE_TYPE_GIF = GlideOptions.decodeTypeOf(GifDrawable.class).lock(); ? ?@GlideType(GifDrawable.class) ? ?
public static void asGIF(RequestBuilder<GifDrawable> requestBuilder) { ? ? ? ?requestBuilder ? ? ? ? ? ? ? ?.transition(new DrawableTransitionOptions()) ? ? ? ? ? ? ? ?.apply(DECODE_TYPE_GIF); ? ?} }
編譯工程逗物,打開build目錄中的GlideRequests,可以看見自動(dòng)生成了一個(gè)方法:
public class GlideRequests extends RequestManager { ?/** ? * @see CustomGlideExtension#asGIF(RequestBuilder) ? */ ?public GlideRequest<GifDrawable> asGIF() { ? ?GlideRequest<GifDrawable> requestBuilder = this.as(GifDrawable.class); ? ?CustomGlideExtension.asGIF(requestBuilder); ? ?return requestBuilder; ?} }現(xiàn)在可以使用你添加的類型了:
GlideApp.with(fragment) ?.asGIF() ?.load(url) ?.into(imageView);4 占位符
占位符就是請(qǐng)求的圖片沒加載出來時(shí)顯示的默認(rèn)圖片瑟俭。?
Glide支持三種不同情況下的占位符:
Placeholder 請(qǐng)求圖片加載中
Error 請(qǐng)求圖片加載錯(cuò)誤
Fallback 請(qǐng)求url/model為空
GlideApp.with(fragment) ?.load(url) ?.placeholder(R.drawable.placeholder) ?.error(new ColorDrawable(Color.RED)) ?.fallback(new ColorDrawable(Color.GREY)) ?.into(view);設(shè)置占位符:
之后的顯示優(yōu)先級(jí)翎卓,我畫了個(gè)流程圖。
5 Options
5.1 RequestOptions
Glide中的大多請(qǐng)求參數(shù)都可以通過RequestOptions類和apply()方法來設(shè)置摆寄。
Glide中的請(qǐng)求參數(shù)主要有:
Placeholders 占位符
Transformations 變換
Caching Strategies 緩存策略
組件特定參數(shù):編碼質(zhì)量失暴,解碼參數(shù)等。
比如微饥,要將圖片的顯示方式設(shè)為CenterCrop逗扒,你可以這么做:
import static com.bumptech.glide.request.RequestOptions.centerCropTransform; Glide.with(fragment) ? ?.load(url) ? ?.apply(centerCropTransform(context)) ? ?.into(imageView);但是其實(shí)完全可以在layout文件中設(shè)置ImageView為android:scaleType="centerCrop",Glide會(huì)自動(dòng)根據(jù)這個(gè)屬性設(shè)置圖片的顯示方式欠橘。
apply方法可以調(diào)用多次矩肩,但是如果兩次apply存在沖突的設(shè)置,會(huì)以最后一次為準(zhǔn)肃续。
5.2 TransitionOptions
TransitionOptions決定圖片加載完成如何從占位符圖片(或者之前的圖片)過渡黍檩。
淡入
交叉淡入
不過渡
注意
TransitionOptions是和你要加載的資源的類型綁定的叉袍,也就是說,如果你請(qǐng)求一張位圖(Bitmap),你就需要使用BitmapTransitionOptions刽酱,而不是DrawableTransitionOptions喳逛。因此,你請(qǐng)求的這張位圖棵里,你需要用簡(jiǎn)單的淡入润文,而不能用?
交叉淡入(DrawableTransitionOptions.withCrossFade())。?
如果既不是Bitmap也不是Drawable可以使用GenericTransitionOptions
5.3 RequestBuilder
作用:
指定加載類型殿怜。asBitmap()典蝌、asGif()、asDrawable()头谜、asFile()骏掀。
指定要加載url/model。
指定要加載到那個(gè)View乔夯。
指定要應(yīng)用的RequestOption
指定要應(yīng)用的TransitionOption
指定要加載的縮略圖
那么如何得到RequestBuilder呢?
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment);默認(rèn)得到一個(gè)Drawable RequestBuilder款侵,如果要指定類型為Bitmap,可以這樣寫:
RequestBuilder<Bitmap> requestBuilder = Glide.with(fragment).asBitmap();應(yīng)用RequestOptions
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment); requestBuilder.apply(requestOptions); requestBuilder.transition(transitionOptions);RequestBuilder也可以重復(fù)使用:
RequestBuilder<Drawable> requestBuilder = ? ? ? ?Glide.with(fragment) ? ? ? ? ? ?.asDrawable() ? ? ? ? ? ?.apply(requestOptions);for (int i = 0; i < numViews; i++) { ? ImageView view = viewGroup.getChildAt(i); ? String url = urls.get(i); ? requestBuilder.load(url).into(view); }6 Transformations
Glide會(huì)自動(dòng)讀取ImageView的縮放類型末荐,所以一般在layout文件指定scaleType即可。
CenterCrop, CenterInside, CircleCrop, FitCenter, RoundedCorners
Glide支持在Java代碼中設(shè)置這些縮放類型:
CenterCrop 縮放寬和高都到達(dá)View的邊界新锈,有一個(gè)參數(shù)在邊界上甲脏,另一個(gè)參數(shù)可能在邊界上,也可能超過邊界
CenterInside 如果寬和高都在View的邊界內(nèi)妹笆,那就不縮放块请,否則縮放寬和高都進(jìn)入View的邊界,有一個(gè)參數(shù)在邊界上拳缠,另一個(gè)參數(shù)可能在邊界上墩新,也可能在邊界內(nèi)
CircleCrop 圓形且結(jié)合了CenterCrop的特性
FitCenter 縮放寬和高都進(jìn)入View的邊界,有一個(gè)參數(shù)在邊界上窟坐,另一個(gè)參數(shù)可能在邊界上海渊,也可能在邊界內(nèi)
RoundedCorners 圓角
有三種用法:
1 使用RequestOptions
RequestOptions options = new RequestOptions(); options.centerCrop(); Glide.with(fragment) ? ?.load(url) ? ?.apply(options) ? ?.into(imageView);2 使用RequestOptions中的transform方法
Glide.with(fragment) ? ?.load(url) ? ?.apply(RequestOptions.fitCenterTransform()) ? ?.into(imageView);3 V4特性
GlideApp.with(fragment) ?.load(url) ?.fitCenter() ?.into(imageView);第三種方法最簡(jiǎn)便,推薦哲鸳。
多個(gè)變換
Glide.with(fragment) ?.load(url) ?.transform(new MultiTransformation(new FitCenter(), new YourCustomTransformation()) ?.into(imageView);7 Transitions(動(dòng)畫)
普通動(dòng)畫
Glide中的過渡動(dòng)畫是指占位符到請(qǐng)求圖片或縮略圖到完整尺寸請(qǐng)求圖片的動(dòng)畫臣疑。過渡動(dòng)畫只能針對(duì)單一請(qǐng)求,不能跨請(qǐng)求執(zhí)行徙菠。
過渡動(dòng)畫執(zhí)行時(shí)機(jī):
1.圖片在磁盤緩存?
2.圖片在本地?
3.圖片在遠(yuǎn)程
如果圖片在內(nèi)存緩存上是不會(huì)執(zhí)行過渡動(dòng)畫的讯沈。如果需要在內(nèi)存緩存上加載動(dòng)畫,可以這樣:
GlideApp.with(this).load(R.drawable.img_default).listener(new RequestListener(){ ? ?@Override ? ?public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { ? ? ? ?return false; ? ?} ? ?@Override ? ?public boolean onResourceReady(Object resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { ? ? ? ?if (dataSource == DataSource.MEMORY_CACHE) { ? ? ? ? ? ?//當(dāng)圖片位于內(nèi)存緩存時(shí)婿奔,glide默認(rèn)不會(huì)加載動(dòng)畫 ? ? ? ? ? ?imageView.startAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.fade_in)); ? ? ? ?} ? ? ? ?return false; ? ?} }).fitCenter().transition(GenericTransitionOptions.with(R.anim.fade_in)).into(imageView);通常的用法如下:
Glide.with(fragment) ? ?.load(url) ? ?.transition(DrawableTransitionOptions.withCrossFade()) ? ?.into(view);TransitionOptions的介紹:TransitionOptions缺狠。有三種TransitionOptions:
GenericTransitionOptions?通用型
DrawableTransitionOptions
BitmapTransitionOptions
如果要使用自定義的動(dòng)畫问慎,可以使用GenericTransitionOptions.with(int viewAnimationId)或者BitmapTransitionOptions.withCrossFade(int animationId, int duration)或者DrawableTransitionOptions.withCrossFade(int animationId, int duration)。
出于性能考慮儒老,最好不要在ListView,GridView,RecycleView中使用過渡動(dòng)畫,使用TransitionOptions.dontTransition()可以不加載動(dòng)畫蝴乔,也可以使用dontAnimate不加載動(dòng)畫
GlideApp.with(mContext) ? ?.load(imgUrl) ? ?.placeholder(R.drawable.img_default) ? ?.dontAnimate() ? ?.into(holder.imageview);自定義過渡動(dòng)畫
1.實(shí)現(xiàn)TransitionFactory?
2.重寫build()?
可以控制圖片在內(nèi)存緩存上是否執(zhí)行動(dòng)畫。
具體寫法參考DrawableCrossFadeFactory驮樊,然后調(diào)用TransitionOptions的with(TransitionFactory transitionFactory)加載薇正。
8 基本配置
8.1 配置內(nèi)存緩存
Glide會(huì)自動(dòng)合理分配內(nèi)存緩存,但是也可以自己手動(dòng)分配囚衔。
方法一
通過MemorySizeCalculator設(shè)置
@GlideModulepublic class CustomGlideModule extends AppGlideModule { ? ?@Override ? ?public void applyOptions(Context context, GlideBuilder builder) { ? ? ? ?MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context) ? ? ? ? ? ? ? ?.setMemoryCacheScreens(2) ? ? ? ? ? ? ? ?.build(); ? ? ? ?builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize())); ? ?} }setMemoryCacheScreens設(shè)置MemoryCache應(yīng)該能夠容納的像素值的設(shè)備屏幕數(shù)挖腰,說白了就是緩存多少屏圖片,默認(rèn)值是2练湿。
方法二
@GlideModulepublic class CustomGlideModule extends AppGlideModule { ? ?@Override ? ?public void applyOptions(Context context, GlideBuilder builder) { ? ? ? ?int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mb ? ? ? ?builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes)); ? ?} }方法三
@GlideModulepublic class YourAppGlideModule extends AppGlideModule { ?@Override ?public void applyOptions(Context context, GlideBuilder builder) { ? ?builder.setMemoryCache(new CustomGlideMemoryCache()); ?} }自己實(shí)現(xiàn)MemoryCache接口猴仑。
清楚內(nèi)存緩存,在主線程調(diào)用:
GlideApp.get(context).clearMemory();8.2 磁盤緩存
Glide使用DiskLruCacheWrapper作為默認(rèn)的磁盤緩存肥哎,默認(rèn)大小是250M,緩存文件放在APP的緩存文件夾下辽俗。
@GlideModulepublic class CustomGlideModule extends AppGlideModule { ? ?@Override ? ?public void applyOptions(Context context, GlideBuilder builder) { ? ? ? ?int diskCacheSizeBytes = 1024 * 1024 * 100; // 100 MB ? ? ? ?builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskCacheSizeBytes));// ? ? ? ?builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "cacheFolderName", diskCacheSizeBytes));// ? ? ? ?builder.setDiskCache(new ExternalCacheDiskCacheFactory(context)); ? ?} }用法如上,可以指定緩存在內(nèi)部存儲(chǔ)或外部存儲(chǔ)篡诽,也可以指定緩存大小和文件夾崖飘。
自定義磁盤緩存
@GlideModulepublic class CustomGlideModule extends AppGlideModule { ?@Override ?public void applyOptions(Context context, GlideBuilder builder) { ? ?builder.setDiskCache(new DiskCache.Factory() { ? ? ? ?@Override ? ? ? ?public DiskCache build() { ? ? ? ? ?return new YourAppCustomDiskCache(); ? ? ? ?} ? ?}); ?} }自己實(shí)現(xiàn)DiskCache接口。
清楚磁盤緩存杈女,在主線程調(diào)用:
GlideApp.get(context).clearDiskCache();8.3 禁止解析Manifest文件
主要針對(duì)V3升級(jí)到v4的用戶朱浴,可以提升初始化速度,避免一些潛在錯(cuò)誤达椰。
@GlideModulepublic class CustomGlideModule extends AppGlideModule { ?@Override ?public boolean isManifestParsingEnabled() { ? ?return false; ?} }8.4 View尺寸
Glide對(duì)ImageView的width和height屬性是這樣解析的:
如果width和height都大于0翰蠢,則使用layout中的尺寸。
如果width和height都是WRAP_CONTENT啰劲,則使用屏幕尺寸梁沧。
如果width和height中至少有一個(gè)值<=0并且不是WRAP_CONTENT,那么就會(huì)在布局的時(shí)候添加一個(gè)OnPreDrawListener監(jiān)聽I(yíng)mageView的尺寸
Glide對(duì)WRAP_CONTENT的支持并不好蝇裤,所以盡量不要用趁尼。
那么如何在運(yùn)行修改ImageView尺寸呢?
方法一 繼承ImageViewTarget
我這里指定的View的類型是ImageView,資源類型是Bitmap猖辫,可根據(jù)需要修改酥泞,onResourceReady(Bitmap bitmap, Transition<? super Bitmap> transition)方法中可以通過bitmap獲取圖片的尺寸。
public class CustomImageViewTarget extends ViewTarget<ImageView, Bitmap> { ? ?private int width, height; ? ?public CustomImageViewTarget(ImageView view) { ? ? ? ?super(view); ? ?} ? ?public CustomImageViewTarget(ImageView view, int width, int height) { ? ? ? ?super(view); ? ? ? ?this.width = width; ? ? ? ?this.height = height; ? ?} ? ?@Override ? ?public void onResourceReady(Bitmap bitmap, Transition<? super Bitmap> transition) { ? ?} ? ?@Override ? ?public void getSize(SizeReadyCallback cb) { ? ? ? ?if (width > 0 && height > 0) { ? ? ? ? ? ?cb.onSizeReady(width, height); ? ? ? ? ? ?return; ? ? ? ?} ? ? ? ?super.getSize(cb); ? ?} }方法二 使用override()
GlideApp.with(mContext) ? ?.load(url) ? ?.override(width,height) ? ?.into(view);8.5 Recycle的加載優(yōu)化
只在拖動(dòng)和靜止時(shí)加載啃憎,自動(dòng)滑動(dòng)時(shí)不加載芝囤。
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { ? ?@Override ? ?public void onScrollStateChanged(RecyclerView recyclerView, int newState) { ? ? ? ?super.onScrollStateChanged(recyclerView, newState); ? ? ? ?switch (newState) { ? ? ? ? ? ?case RecyclerView.SCROLL_STATE_DRAGGING: ? ? ? ? ? ? ? ?GlideApp.with(context).resumeRequests(); ? ? ? ? ? ? ? ?break; ? ? ? ? ? ?case RecyclerView.SCROLL_STATE_SETTLING: ? ? ? ? ? ? ? ? ? ? ? ?GlideApp.with(context).pauseRequests(); ? ? ? ? ? ? ? ? ? ? ? ?break; ? ? ? ? ? ?case RecyclerView.SCROLL_STATE_IDLE: ? ? ? ? ? ? ? ?GlideApp.with(context).resumeRequests(); ? ? ? ? ? ? ? ?break; ? ? ? ?} ? ?} });