集成
配置
app gradle中:
repositories { mavenCentral() google() }
implementation 'com.github.bumptech.glide:glide:4.5.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.5.0'
混淆
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# for DexGuard only
-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
用法
基本用法
Glide.with(fragment) .load(myUrl) .into(imageView);
自定义方法
v4特性
v4中Glide.with().load()
不能配合fitCenter
和placeholder
使用,取而代之以一种更巧妙的方法来实现相同的功能:
annotation processor
动态生成API,允许应用修改RequestBuilder
、RequestOptions
和任意的包含在单一流式API库中的方法
实现:
GlideApp.with(fragment) //GlideApp 是动态实现的类 后面会具体分析
.load(myUrl)
.placeholder(R.drawable.placeholder)
.fitCenter()
.into(imageView);
(annotation processor
:注解处理器,代替原来的APT,AOP的一种实现方式)
思考:这样设计相对于之前有什么优势?
我自己的理解是这样具有更强的拓展性:
1.对于设计者而言可以继承Glide的API实现自定义的方法
2.对于使用者而言继承Glide的API后可以实现自定义的方法
如何自定义?
实现AppGlideModule
@GlideModule
public class CustomGlideModule extends AppGlideModule {}
编译项目后查看项目结构,build下多出了四个类,这四个类正是利用annotation processor
动态生成的:
这里出现了上文提到的GlideApp,查看源码可知,此类相当于Glide的代理类
GlideExtension
为了添加新的方法,修改已有的方法或者添加对其他类型格式的支持,我们需要在拓展中使用加了注解的静态方法
GlideOption
用来添加自定义的方法,GlideType
用来支持新的格式
GlideOption
新建CustomGlideExtension:
@GlideExtension
public class CustomGlideExtension {
//缩略图的最小尺寸,单位:px
private static final int MINI_THUMB_SIZE = 100;
/**
* 将构造方法设为私有,作为工具类使用
*/
private CustomGlideExtension() {
}
/**
* 1.自己新增的方法的第一个参数必须是RequestOptions options
* 2.方法必须是静态的
* @param options
*/
@GlideOption
public static void miniThumb(RequestOptions options) {
options
.fitCenter()
.override(MINI_THUMB_SIZE);
}
}
编译工程,打开build目录中的GlideOptions,可以看见自动生成了两个方法:
/**
* @see CustomGlideExtension#miniThumb(RequestOptions)
*/
@NonNull
@CheckResult
public GlideOptions miniThumb() {
if (isAutoCloneEnabled()) {
return clone().miniThumb();
}
CustomGlideExtension.miniThumb(this);
return this;
}
/**
* @see CustomGlideExtension#miniThumb(RequestOptions)
*/
@CheckResult
public static GlideOptions miniThumbOf() {
return new GlideOptions().miniThumb();
}
使用以上自定义的方法:
GlideApp.with(fragment)
.load(url)
.miniThumb(thumbnailSize)
.into(imageView);
GlideType
以对GIF格式的支持为例(实际上Glide的API中已经实现)
在刚才的CustomGlideExtension
类中加上:
@GlideExtension
public 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
/**
* @see CustomGlideExtension#asGIF(RequestBuilder)
*/
@NonNull
@CheckResult
public GlideRequest<GifDrawable> asGIF() {
GlideRequest<GifDrawable> requestBuilder = this.as(GifDrawable.class);
CustomGlideExtension.asGIF(requestBuilder);
return requestBuilder;
}
使用:
GlideApp.with(this)
.asGIF()
.load(url)
.into(iv_test1);
占位图
三种占位图:
- Placeholder 请求图片加载中
- Error 请求图片加载错误
- Fallback 请求url/model为空
Options
RequestOptions
Glide中的大多请求参数都可以通过RequestOptions类和apply()方法来设置
Glide中的请求参数主要有:
- Placeholders 占位符
- Transformations 变换
- Caching Strategies 缓存策略
- 组件特定参数:编码质量,解码参数等
将图片设置为CenterCrop:
import static com.bumptech.glide.request.RequestOptions.centerCropTransform;
Glide.with(fragment)
.load(url)
.apply(centerCropTransform(context))
.into(imageView);
注:其实Glide会自动根据layout
文件中设置的属性设置图片的显示方式 所以在layout
文件中设置ImageView
为android:scaleType="centerCrop"
可以达到相同的效果
TransitionOptions
TransitionOptions
决定图片加载完成如何从占位图(或者之前的图片)过渡
三种过度方式:
淡入
交叉淡入
不过渡
Glide.with(fragment)
.load(url)
.transition(DrawableTransitionOptions.withCrossFade())
.into(view);
RequestBuilder
作用:
- 指定加载类型。asBitmap()、asGif()、asDrawable()、asFile()
- 指定要加载url/model
- 指定要加载到那个View
- 指定要应用的RequestOption
- 指定要应用的TransitionOption
- 指定要加载的缩略图
获取RequestBuilder:
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment);
默认得到一个Drawable RequestBuilder
,,如果要指定类型为Bitmap,可以这样写:
RequestBuilder<Bitmap> requestBuilder = Glide.with(fragment).asBitmap();
应用RequestOptions
:
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment);
requestBuilder.apply(requestOptions);
requestBuilder.transition(transitionOptions);
Transformations
Glide会自动读取ImageView
的缩放类型,所以一般在layout
文件指定scaleType
即可
CenterCrop
, CenterInside
,CircleCrop
, FitCenter
, RoundedCorners
三种用法:
- 使用RequestOptions
RequestOptions options = new RequestOptions();
options.centerCrop();
Glide.with(fragment)
.load(url)
.apply(options)
.into(imageView);
- 使用RequestOptions中的transform方法
Glide.with(fragment)
.load(url)
.apply(RequestOptions.fitCenterTransform())
.into(imageView);
- V4特性 (推荐)
GlideApp.with(fragment)
.load(url)
.fitCenter()
.into(imageView);
Transitions(动画)
普通动画
过渡动画是指占位图到请求图片或者缩略图到完整图片的动画 过渡动画只能针对单一请求 不能跨请求
执行时机:
- 图片在磁盘缓存
- 图片在本地
- 图片在远程
默认图片在内存缓存上是不会执行过渡动画
在内存缓存上加载动画:
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) {
//当图片位于内存缓存时,glide默认不会加载动画
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:
- GenericTransitionOptions 通用型
- DrawableTransitionOptions
- BitmapTransitionOptions
使用自定义动画:
GenericTransitionOptions.with(int viewAnimationId)
或者BitmapTransitionOptions.withCrossFade(int animationId, int duration)
或者DrawableTransitionOptions.withCrossFade(int animationId, int duration)
处于性能考虑,不要在ListView
,GridView
,RecycleView
中使用过渡动画,
TransitionOptions.dontTransition()
或者dontAnimate
不加载动画
自定义过渡动画
1.实现TransitionFactory
2.重写build()
可以控制图片在内存缓存上是否执行动画
基本配置
配置内存缓存
Glide会自动合理分配内存缓存,也可以手动分配
三种方法
- 通过
MemorySizeCalculator
设置
@GlideModule
public 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()));
}
}
- 手动定义大小
@GlideModule
public class CustomGlideModule extends AppGlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mb
builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));
}
}
- 自己实现MemoryCache接口
@GlideModulepublicclass YourAppGlideModule extends AppGlideModule {@OverridepublicvoidapplyOptions(Context context, GlideBuilder builder) {
builder.setMemoryCache(new CustomGlideMemoryCache());
}
}
清除内存缓存(需要在主线程中调用):
GlideApp.get(context).clearMemory();
跳过内存缓存:
GlideApp.with(getActivity())
.load(url)
.skipMemoryCache(true)
.dontAnimate()
.centerCrop()
.into(imageView);
磁盘缓存
Glide使用DiskLruCacheWrapper
作为默认的磁盘缓存:
@GlideModule
public 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));
}
}
以上 指定内部缓存还是外部缓存 指定缓存的大小和文件夹
自定义磁盘缓存:自己实现DiskCache接口
清除磁盘缓存(主线程中调用):
GlideApp.get(context).clearDiskCache();
设置磁盘缓存策略:
GlideApp.with(getActivity())
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.dontAnimate()
.centerCrop()
.into(imageView);
默认的策略:DiskCacheStrategy.AUTOMATIC
DiskCacheStrategy
五个常量:
-
DiskCacheStrategy.ALL
使用DATA
和RESOURCE
缓存远程数据,仅使用RESOURCE
来缓存本地数据 -
DiskCacheStrategy.NONE
不使用磁盘缓存 -
DiskCacheStrategy.DATA
在资源解码前就将原始数据写入磁盘缓存 -
DiskCacheStrategy.RESOURCE
在资源解码后将数据写入磁盘缓存,即经过缩放等转换后的图片资源
-DiskCacheStrategy.AUTOMATIC
根据原始图片数据和资源编码策略来自动选择磁盘缓存策略
禁止解析manifest
文件
主要针对v3升级到v4 可以提升初始化速度 避免一些潜在错误
@GlideModule
public class CustomGlideModule extends AppGlideModule {
@Override
public boolean isManifestParsingEnabled() {
return false;
}
}
View尺寸
Glide对Imageview
的width
和height
属性的解析逻辑:
如果
width
和height
都大于0,则使用layout
中的尺寸。如果
width
和height
都是WRAP_CONTENT
,则使用屏幕尺寸。如果
width
和height
中至少有一个值<=0并且不是WRAP_CONTENT
,那么就会在布局的时候添加一个OnPreDrawListener
监听ImageView
的尺寸
Glide对WRAP_CONTENT
支持不好 尽量不用
运行时修改ImageView尺寸两种方法:
- 继承
ImageViewTarget
public class CustomImageViewTarget extends ImageViewTarget<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) {
super.onResourceReady(bitmap,transition);
}
@Override
protected void setResource(@Nullable Bitmap resource) {
view.setImageBitmap(resource);
}
@Override
public void getSize(SizeReadyCallback cb) {
if (width > 0 && height > 0) {
cb.onSizeReady(width, height);
return;
}
super.getSize(cb);
}
}
GlideApp.with(context)
.asBitmap()
.load(url)
.dontAnimate()
.placeholder(R.drawable.img_default)
.into(new CustomImageViewTarget(imageview, 300, 300));
- override()
GlideApp.with(mContext)
.load(url)
.override(width,height)
.into(view);