关于Glide v4 使用

集成

配置

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()不能配合fitCenterplaceholder使用,取而代之以一种更巧妙的方法来实现相同的功能:
annotation processor 动态生成API,允许应用修改RequestBuilderRequestOptions和任意的包含在单一流式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动态生成的:

image.png

这里出现了上文提到的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文件中设置ImageViewandroid: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使用DATARESOURCE缓存远程数据,仅使用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对Imageviewwidthheight属性的解析逻辑:

  • 如果widthheight都大于0,则使用layout中的尺寸。

  • 如果widthheight都是WRAP_CONTENT,则使用屏幕尺寸。

  • 如果widthheight中至少有一个值<=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);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容