Glide4.x使用总结

基础

基础用法

Glide.with(this)
     .load(url) //资源地址 本地uri,网络资源,图片路径
     .asGif() // 指定资源样式 还可以asBitmap(),但是glide会自动判断,非特殊情况不用指定
     .placeholder(R.drawable.loading) //加载过程显示
     .error(R.drawable.error) // 加载错误显示
     .diskCacheStrategy(DiskCacheStrategy.NONE) //缓存设置
     .centerCrop() // 图片剪切样式
     .priority(Priority.HIGH) //加载优先级
     .thumbnail(0.2f) //缩略图,显示较小图片时用
     .override(100, 100) //指定图片大小,这样可以节省内存消耗
     .into(imageView);

清理缓存

Glide.get(context).clearDiskCache();//清理磁盘缓存 需要在子线程中执行 
Glide.get(context).clearMemory();//清理内存缓存 可以在UI主线程中进行

停止/重启请求

    Glide.with(context).resumeRequests();
    Glide.with(context).resumeRequestsRecursive();
    Glide.with(context).pauseRequests();
    Glide.with(context).pauseAllRequests();

基处知识

内存使用量计算

ARGB_8888 :32位图,带透明度,每个像素占4个字节
ARGB_4444 :16位图,带透明度,每个像素占2个字节
RGB_565 :16位图,不带透明度,每个像素占2个字节
ALPHA_8 :32位图,只有透明度,不带颜色,每个像素占4个字节

glide 默认使用RGB_565加载 一张4000 * 2000图片

4000 * 2000 * 2(Byte) / 1024 / 1024 = 15 (MB)

缓存

Glide不仅仅缓存文件,还会缓存与缓存文件相关的内容,如图片大小,使用时应用的变化和设置等等

选项

Requestions

RequestOptions cropOptions = new RequestOptions().centerCrop(context);
...
Glide.with(fragment)
    .load(url)
    .apply(cropOptions)
    .into(imageView);
  1. apply() 方法可以被调用多次,因此 RequestOption 可以被组合使用
  2. 如果 RequestOptions 对象之间存在相互冲突的设置,那么只有最后一个被应用的 RequestOptions 会生效。

bitmapTransform 把bitmap转变为各种样式

  Glide.with(context)
        .load(headUrl + url)
        .apply(RequestOptions.bitmapTransform(new CircleCrop()))
        .into(imageView);

TransitionOptions

使用场景

  1. view淡入
  2. 占位符交叉淡入
import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;

Glide.with(fragment)
    .load(url)
    .transition(withCrossFade())
    .into(view);

使用动画效果

ViewPropertyAnimation.Animator animationObject = new ViewPropertyAnimation.Animator() {  
    @Override
    public void animate(View view) {
        // if it's a custom view class, cast it here
        // then find subviews and do the animations
        // here, we just use the entire view for the fade animation
        view.setAlpha( 0f );

        ObjectAnimator fadeAnim = ObjectAnimator.ofFloat( view, "alpha", 0f, 1f );
        fadeAnim.setDuration( 2500 );
        fadeAnim.start();
    }
};

GlideApp  
    .with(context)
      .load(eatFoodyImages[1])
      .transition(GenericTransitionOptions.with(animationObject))
//      .transition(GenericTransitionOptions.with(R.anim.zoom_in)) 支持xml形式
      .into(imageView2);
  1. BitmapTransitionOptions
  2. DrawableTransitionOptions

RequestBuilder

  • 你想加载的资源类型(Bitmap, Drawable, 或其他)
  • 你要加载的资源地址(url/model)
  • 你想最终加载到的View
  • 任何你想应用的(一个或多个)RequestOption 对象
  • 任何你想应用的(一个或多个)TransitionOption 对象
  • 任何你想加载的缩略图 thumbnail()
//构造
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment).asDrawable();
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment).load(url);
//as.. 选择资源类型
RequestBuilder<Bitmap> requestBuilder = Glide.with(fragment).asBitmap();
//requestOptions transition
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment).asDrawable();
requestBuilder.apply(requestOptions);
requestBuilder.transition(transitionOptions);

//复用
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);
}

缩略图 (Thumbnail) 请求

优先加载本地低分辨率图,在加载无损版本

Glide.with(fragment)
  .load(url)
  .thumbnail( 
    //.override 设置本地版本加载大小
    Glide.with(fragment).load(thumbnailUrl)
    )
  .into(imageView);

在失败时开始新的请求

Glide.with(fragment)
  .load(primaryUrl)
  .error(Glide.with(fragment)
      .load(fallbackUrl))
  .into(imageView);

组件选项

Option 类是给Glide的组件添加参数的通用办法,包括 ModelLoaders , ResourceDecoders , ResourceEncoders , Encoders 等等

用法设置请求超时时间

Glide.with(context)
  .load(url)
  .option(MyCustomModelLoader.TIMEOUT_MS, 1000L)
  .into(imageView);

RequestOptions options = new RequestOptions()
  .set(MyCustomModelLoader.TIMEOUT_MS, 1000L);

Glide.with(context)
  .load(url)
  .apply(options)
  .into(imageView);

Transformations

内置类型

Glide.with(fragment)
  .load(url)
  .fitCenter()
  .into(imageView);

RequestOptions options = new RequestOptions();
options.centerCrop();

Glide.with(fragment)
    .load(url)
    .apply(options)
    .into(imageView);

多重变换

Glide.with(fragment)
  .load(url)
  // .transform(new FitCenter(), new YourCustomTransformation())
  .transform(new MultiTransformation(new FitCenter(), new YourCustomTransformation())
  .into(imageView);

【注意】: 传入变换参数的顺序,决定了这些变换的应用顺序

定制变换

CircleCrop.java

public class CircleCrop extends BitmapTransformation {
  // The version of this transformation, incremented to correct an error in a previous version.
  // See #455.
  private static final int VERSION = 1;
  private static final String ID = "com.bumptech.glide.load.resource.bitmap.CircleCrop." + VERSION;
  private static final byte[] ID_BYTES = ID.getBytes(CHARSET);

  // Bitmap doesn't implement equals, so == and .equals are equivalent here.
  @SuppressWarnings("PMD.CompareObjectsWithEquals")
  @Override
  protected Bitmap transform(
      @NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
    return TransformationUtils.circleCrop(pool, toTransform, outWidth, outHeight);
  }

  @Override
  public boolean equals(Object o) {
    return o instanceof CircleCrop;
  }

  @Override
  public int hashCode() {
    return ID.hashCode();
  }

  @Override
  public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
    messageDigest.update(ID_BYTES);
  }
}

使用

    Glide.with(context)
        .load(headUrl + url)
        .apply(RequestOptions.bitmapTransform(new CircleCrop()))
        .into(imageView);

Target

常用的实现类 ViewTarget、 ImageViewTargets 、DrawableImageViewTarget

Target<Drawable> target = 
   Glide.with(context)
        .load(url)
        .into(new Target<Drawable>() {

          @Override public void onStart() {

          }

          @Override public void onStop() {

          }

          @Override public void onDestroy() {

          }

          @Override public void onLoadStarted(@Nullable Drawable placeholder) {

          }

          @Override public void onLoadFailed(@Nullable Drawable errorDrawable) {

          }

          @Override public void onResourceReady(@NonNull Drawable resource,
              @Nullable Transition<? super Drawable> transition) {

          }

          @Override public void onLoadCleared(@Nullable Drawable placeholder) {

          }

          @Override public void getSize(@NonNull SizeReadyCallback cb) {

          }

          @Override public void removeCallback(@NonNull SizeReadyCallback cb) {

          }

          @Override public void setRequest(@Nullable Request request) {

          }

          @Nullable @Override public Request getRequest() {
            return null;
          }
        });

取消和重用

  • Glide.with(fragment).clear(target); 返回的 Targetclear() 之前的加载,这将在不需要开始新的加载的情况下释放掉任何相关资源:
  • 仅对ViewTarget而言,你可以在每次加载或清理调用时都传入一个新的实例,而 Glide 仍然可以从 View 的 tag 中取回之前一次加载的信息,从而达到复用的效果
Glide.with(fragment)
  .load(url)
  .into(new DrawableImageViewTarget(imageView));

// Some time in the future:
Glide.with(fragment)
  .load(newUrl)
  .into(new DrawableImageViewTarget(imageView));

尺寸 (Sizes and dimensions)

默认情况下,Glide 使用目标通过 getSize 方法提供的尺寸来作为请求的目标尺寸。这允许 Glide 选取合适的 URL,下采样,裁剪和变换合适的图片以减少内存占用,并确保加载尽可能快地完成。

ViewTarget 通过检查 View 的属性和/或使用一个 OnPreDrawListener 在 View 绘制之前直接测量尺寸来实现 getSize() 方法。因此, Glide 可以自动调整大部分图片以匹配目标 View

请参考 ViewTarget 中的逻辑。

动画资源和定制目标

Glide.with(fragment)
  .asGif()
  .load(url)
  .into(new SimpleTarget<>() {
    @Override
    public void onResourceReady(GifDrawable resource, Transition<GifDrawable> transition) {
        //gif 
        if (resource instanceof Animatable) {
        resource.start();
      }
    }
  });

过渡

允许你定义 Glide 如何从占位符到新加载的图片,或从缩略图到全尺寸图像过渡。

  1. 4.x 默认不会使用交叉淡入动画
  2. 过渡动画效果在安卓中消耗 比较大需要谨慎使用

定制过渡

请查看 DrawableCrossFadeFactory.

配置

  1. AppGlideModule 全局唯一,多个冲突
  2. LibraryGlideModule 可添加多个

基本用法

加入依赖

compile 'com.github.bumptech.glide:annotations:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

混淆

-keep public class  extends com.bumptech.glide.module.AppGlideModule
-keep class com.bumptech.glide.GeneratedAppGlideModuleImpl

在 Glide 的 Flickr 示例应用

@GlideModule
public class FlickrGlideModule extends AppGlideModule {
  @Override
  public void registerComponents(Context context, Registry registry) {
    // Photo.class 是一个普通的bean
    registry.append(Photo.class, InputStream.class, new FlickrModelLoader.Factory());
  }
}
@GlideModule
public final class OkHttpLibraryGlideModule extends LibraryGlideModule {
  @Override
  public void registerComponents(Context context, Glide glide, Registry registry) {
    registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
  }
}

应用程序选项

GlideBuilder 属性

  • .setMemoryCache(MemoryCache memoryCache)
  • .setBitmapPool(BitmapPool bitmapPool)
  • .setDiskCache(DiskCache.Factory diskCacheFactory)
  • .setDiskCacheService(ExecutorService service)
  • .setResizeService(ExecutorService service)
  • .setDecodeFormat(DecodeFormat decodeFormat)
@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
      //自定义 MemoryCache 的大小
    MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context)
        .setMemoryCacheScreens(2)
        .build();
    builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize()));
      //直接覆写缓存大小
       int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mb
    builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));

  }
}

Bitmap 池

YourAppGlideModule{ 
MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context)
        .setBitmapPoolScreens(3)
        .build();
    builder.setBitmapPool(new LruBitmapPool(calculator.getBitmapPoolSize()));
      int bitmapPoolSizeBytes = 1024 * 1024 * 30; // 30mb
    builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));
}

磁盘缓存 默认磁盘大小为 250 MB

//存位置改到外部存储 
builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
//改变磁盘缓存的大小:
int diskCacheSizeBytes = 1024  1024  100;  100 MB
builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskCacheSizeBytes));

默认请求选项

  1. 全局生效
  2. 会覆盖之前设置

方式一, APPGlideModule设置方式

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDefaultRequestOptions(
        new RequestOptions()
          .format(DecodeFormat.RGB_565)
          .disallowHardwareBitmaps());
  }
}

方式二. RequestOptions

Glide.with(fragment)
  .applyDefaultRequestOptions(
      new RequestOptions()
          .format(DecodeFormat.RGB_565)
          .disallowHardwareBitmaps());

注册组件

  1. ModelLoader, 用于加载自定义的 Model(Url, Uri,任意的 POJO )和 Data(InputStreams, FileDescriptors)。
  2. ResourceDecoder, 用于对新的 Resources(Drawables, Bitmaps)或新的 Data 类型(InputStreams, FileDescriptors)进行解码。
  3. Encoder, 用于向 Glide 的磁盘缓存写 Data (InputStreams, FileDesciptors)。
  4. ResourceTranscoder,用于在不同的资源类型之间做转换,例如,从 BitmapResource 转换为 DrawableResource 。
  5. ResourceEncoder,用于向 Glide 的磁盘缓存写 Resources(BitmapResource, DrawableResource)。
@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void registerComponents(Context context, Registry registry) {
      //prepend
      //replace
    registry.append(Photo.class, InputStream.class, new CustomModelLoader.Factory());
  }
}

案例:ModelLoaderResourceDecoder

实践案例

  1. 提高glide图片加载质量

Android 中有两个主要的方法对图片进行解码:ARGB8888 和 RGB565。前者为每个像素使用了 4 个字节,后者仅为每个像素使用了 2 个字节。ARGB8888 的优势是图像质量更高以及能存储一个 alpha 通道。Glide 默认使用低质量的 RGB565

public class SimpleGlideModule implements GlideModule {  
    @Override public void applyOptions(Context context, GlideBuilder builder) {
        builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
    }

    @Override public void registerComponents(Context context, Glide glide) {
        // nothing to do here
    }
}
  1. Module 实例:接受自签名证书的 HTTPS

其他配置

未捕获异常策略

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    final UncaughtThrowableStrategy myUncaughtThrowableStrategy = new ...
    builder.setDiskCacheExecutor(newDiskCacheExecutor(myUncaughtThrowableStrategy));
    builder.setResizeExecutor(newSourceExecutor(myUncaughtThrowableStrategy));
  }
}

日志级别

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setLogLevel(Log.DEBUG);
  }
}

缓存

缓存四个级别

Active Resources(View 正在显示) > Memory cache(加载过并在内存) > Resource(解密并存在磁盘) > Data (曾经写入过文件)

配置缓存

Glide.with(fragment)
  .load(url)
   //.onlyRetrieveFromCache(true)
   //.skipMemoryCache(true)
    //.diskCacheStrategy(DiskCacheStrategy.NONE)
  .diskCacheStrategy(DiskCacheStrategy.ALL)
  .into(imageView);

定制缓存刷新Key值

文件 ObjectKey

Glide.with(yourFragment)
    .load(yourFileDataModel)
    .signature(new ObjectKey(yourVersionMetadata/*修改日期*/))
    .into(yourImageView);

媒体存储签名MediaStore

Glide.with(fragment)
    .load(mediaStoreUri)
    .signature(new MediaStoreSignature(mimeType, dateModified, orientation))
    .into(view);

定义你自己的签名

public class IntegerVersionSignature implements Key {
    private int currentVersion;

    public IntegerVersionSignature(int currentVersion) {
         this.currentVersion = currentVersion;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof IntegerVersionSignature) {
            IntegerVersionSignature other = (IntegerVersionSignature) o;
            return currentVersion == other.currentVersion;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return currentVersion;
    }

    @Override
    public void updateDiskCacheKey(MessageDigest md) {
        messageDigest.update(ByteBuffer.allocate(Integer.SIZE).putInt(signature).array());
    }
}

组件

常用的组件概述

  1. ModelLoader

    A factory interface for translating an arbitrarily complex data model into a

    concrete data type that can be used by an DataFetcher to obtain the data for a resource represented by the model.

  2. ResourceDecoder<T,Z>

    T - The type the resource will be decoded from (File, InputStream etc).

    Z - The type of the decoded resource (Bitmap, Drawable etc).

  3. ResourceEncoder

    T - The type of the data contained by the resource.

案例

1. 加载加载角图片

开源库

glide-transformations

2. 下载文件/获取缓存文件路径

FutureTarget<File> target = Glide.with(context).load(url).downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
final File imageFile = target.get();

3. 根据加载的资源动态设置ImageView大小

主要是RequestListener 的应用, 获取资源的数据resource.getIntrinsicHeight()

    /**
     * 自适应宽度加载图片。保持图片的长宽比例不变,通过修改imageView的高度来完全显示图片。
     */
    public static void loadIntoUseFitWidth(Context context, final String imageUrl, int errorImageId, final ImageView imageView) {
        Glide.with(context)
                .load(imageUrl)
                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                .listener(new RequestListener<String, GlideDrawable>() {
                    @Override
                    public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                        if (imageView == null) {
                            return false;
                        }
                        if (imageView.getScaleType() != ImageView.ScaleType.FIT_XY) {
                            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
                        }
                        ViewGroup.LayoutParams params = imageView.getLayoutParams();
                        int vw = imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight();
                        float scale = (float) vw / (float) resource.getIntrinsicWidth();
                        int vh = Math.round(resource.getIntrinsicHeight() * scale);
                        params.height = vh + imageView.getPaddingTop() + imageView.getPaddingBottom();
                        imageView.setLayoutParams(params);
                        return false;
                    }
                })
                .placeholder(errorImageId)
                .error(errorImageId)
                .into(imageView);
    }

4. 【官方】编写定制的 ModelLoader

相关开源库

参考

附录