Android Glide 的简单使用(一)(下)

简介: Generated API使用Generated API(高级用法)定制请求GlideExtensionGlideOptionGlideTypesubmit同步获取图片资源Application Options(选项)Memory cache(内存缓存)Disk Cache(磁盘缓存)Bitmap pool(位图池)配置缓存磁盘缓存策略(Disk Cache Strategy)仅从缓存加载图片跳过缓存清理磁盘缓存相关资源Glide 缓存机制及源码(二)Glide git传送门Glide中文文档glide-transformations传送门

Generated API


       Glide v4 使用 注解处理器 (Annotation Processor) 来生成出一个 API,它允许应用扩展 Glide 的 API并包含各种集成库提供的组件。


Generated API 模式的设计出于以下两个目的:


  • 1.集成库可以为 Generated API 扩展自定义选项。


  • 2.在 Application 模块中可将常用的方法组打包成一个选项在 Generated API 中使用


       虽然以上所说的工作均可以通过手动创建 RequestOptions 子类的方式来完成,但想将它用好更具有挑战,并且降低了 API 使用的流畅性。


使用Generated API(高级用法)


      1.在build.gradle中添加依赖


annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'


 2.创建一个添加有 @GlideModule 注解,继承自 AppGlideModule 的类。此类可生成出一个流式 API,内联了多种选项和集成库中自定义的选项:


@GlideModule
public class MyGlideModule extends AppGlideModule 
{
}


 3.生成的 API 默认名为 GlideApp ,与 AppGlideModule 的子类包名相同。在 Application 模块中将 Glide.with() 替换为 GlideApp.with(),即可使用该 API 去完成加载工作。


GlideApp.with(this).load(uri).circleCrop().into(agb.ivCirclecrop);


       Android Studio 在大多数时候都可以正确地处理注解处理器 (annotation processor) 和 generated API。然而,当你第一次添加你的 AppGlideModule 或做了某些类型的修改后,你可能需要重新构建 (rebuild) 你的项目。 如果你发现 API 没有被 import ,你可以通过以下方法重新构建:


  • 1.打开 Build 菜单;


  • 2.点击 Rebuild Project。


定制请求


       Glide 提供了许多可应用于单一请求的选项,包括变换、过渡、缓存选项等。


     1.默认选项可以直接应用于请求上:

GlideApp.with(this).load(uri)
    .placeholder(R.mipmap.sc2)
    .error(R.mipmap.sc1)
    .override(150)
    .circleCrop().into(agb.ivOptions);


      2.通过 RequestOptions 类来在多个请求之间共享:


RequestOptions requestOptions = new RequestOptions().circleCrop()
.placeholder(R.mipmap.sc2)
.error(R.mipmap.sc1).override(150);
        GlideApp.with(this).load(uri).apply(requestOptions).into(agb.ivOptions);      
GlideApp.with(this).load(uri).apply(requestOptions).into(agb.ivCirclecrop);


GlideExtension


       Glide Generated API 可在 Application 和 Library 中被扩展。扩展使用被注解的静态方法来添加新的选项、修改现有选项、甚至添加额外的类型支持。


       被 @GlideExtension 注解的类应以工具类的思维编写。这种类应该有一个私有的、空的构造方法,应为 final 类型,并且仅包含静态方法。被注解的类可以含有静态变量,可以引用其他的类或对象。


被 @GlideExtention 注解的类有两种扩展方式:


  • GlideOption - 为 RequestOptions 添加一个自定义的选项。


  • GlideType - 添加对新的资源类型的支持(GIF,SVG 等等)。


GlideOption


     1.创建一个添加有 @GlideExtension注解的类。此类可生成出一个流式 API,内联了多种选项和集成库中自定义的选项:


@GlideExtension
public final class MyGlideExtension {
    private MyGlideExtension(){}
    @GlideOption
    public static BaseRequestOptions<?> applyHeadScc(BaseRequestOptions<?> options,int size){
        return options.circleCrop()
                .override(size)
                .placeholder(R.mipmap.sc2)
                .error(R.mipmap.sc1);
    }
}


  2.这将在RequestOptions子类中生成一个如下所示的方法:


public class GlideOptions extends RequestOptions {
  /**
   * @see MyGlideExtension#applyHeadScc(BaseRequestOptions, int)
   */
  @SuppressWarnings("unchecked")
  @CheckResult
  @NonNull
  public GlideOptions applyHeadScc(int size) {
    return (GlideOptions) MyGlideExtension.applyHeadScc(this, size);
  }
  ...
}


3.可以根据需要在方法中包含任意数量的附加参数,只要第一个参数始终为RequestOptions:


@GlideOption
    public static BaseRequestOptions<?> applyHeadScc(BaseRequestOptions<?> options,int size){
        return options.circleCrop()
                .override(size)
                .placeholder(R.mipmap.sc2)
                .error(R.mipmap.sc1);
}


     4.附加参数将作为参数添加到生成的方法中:


public GlideOptions applyHeadScc(int size) {
    return (GlideOptions) MyGlideExtension.applyHeadScc(this, size);
  }


      5.使用生成的GlideApp类调用你的自定义方法:


GlideApp.with(this)
  .load(uri)
  .applyHeadScc(150)
  .into(agb.ivOptions);


       带有GlideOption注释的方法应该是静态的并返回BaseRequestOptions< ? > 注意: 生成的方法在标准Glide和RequestOptions类上不可用,只有Generated 的等效项可用。


高斯模糊(效果图)


微信图片_20220521212442.png


1.使用库传送门


implementation 'jp.wasabeef:glide-transformations:4.3.0'


       开始使用


    @GlideOption
    public static BaseRequestOptions<?> applyBlurHeadScc(BaseRequestOptions<?> options,int size){
        BlurTransformation blurTransformation = new BlurTransformation(20,1);
        return options
                .override(size)
                .placeholder(R.mipmap.sc2)
                .error(R.mipmap.sc1)
//                .circleCrop()
//                .transform(blurTransformation);
//      .transform(blurTransformation,new CircleCrop());
                .transform(new MultiTransformation<>(blurTransformation,new CircleCrop()));
}


   注意: 默认情况下,对每一个后续呼叫transform()或任何特定的transform方法(fitCenter(),centerCrop(),bitmapTransform()等)将取代先前的transform。


 要将多个转换应用于单个加载,请使用MultiTransformation类或快捷 .transforms() 方法。


       2.自定义Transformation 你也可以继承BitmapTransformation,重写transform方法,下面贴出glide-transformations里面的BlurTransformation类,一起学习一下。


public class BlurTransformation extends BitmapTransformation {
  private static final int VERSION = 1;
  private static final String ID =
    "jp.wasabeef.glide.transformations.BlurTransformation." + VERSION;
  private static final int MAX_RADIUS = 25;
  private static final int DEFAULT_DOWN_SAMPLING = 1;
  private final int radius;
  private final int sampling;
  public BlurTransformation() {
    this(MAX_RADIUS, DEFAULT_DOWN_SAMPLING);
  }
  public BlurTransformation(int radius) {
    this(radius, DEFAULT_DOWN_SAMPLING);
  }
  public BlurTransformation(int radius, int sampling) {
    this.radius = radius;
    this.sampling = sampling;
  }
  @Override
  protected Bitmap transform(@NonNull Context context, @NonNull BitmapPool pool,
                             @NonNull Bitmap toTransform, int outWidth, int outHeight) {
    int width = toTransform.getWidth();
    int height = toTransform.getHeight();
    int scaledWidth = width / sampling;
    int scaledHeight = height / sampling;
    Bitmap bitmap = pool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
    setCanvasBitmapDensity(toTransform, bitmap);
    Canvas canvas = new Canvas(bitmap);
    canvas.scale(1 / (float) sampling, 1 / (float) sampling);
    Paint paint = new Paint();
    paint.setFlags(Paint.FILTER_BITMAP_FLAG);
    canvas.drawBitmap(toTransform, 0, 0, paint);
    try {
      bitmap = RSBlur.blur(context, bitmap, radius);
    } catch (RSRuntimeException e) {
      bitmap = FastBlur.blur(bitmap, radius, true);
    }
    return bitmap;
  }
  @Override
  public String toString() {
    return "BlurTransformation(radius=" + radius + ", sampling=" + sampling + ")";
  }
  @Override
  public boolean equals(Object o) {
    return o instanceof BlurTransformation &&
      ((BlurTransformation) o).radius == radius &&
      ((BlurTransformation) o).sampling == sampling;
  }
  @Override
  public int hashCode() {
    return ID.hashCode() + radius * 1000 + sampling * 10;
  }
  @Override
  public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
    messageDigest.update((ID + radius + sampling).getBytes(CHARSET));
  }
}


GlideType


       GlideType带注释的静态方法扩展RequestManager。GlideType带注释的方法允许您添加对新类型的支持,包括指定默认选项。


      1.例如,要添加对 GIF 的支持(选择资源类型),你可以添加一个GlideType方法:


    @GlideType(GifDrawable.class)
    public static RequestBuilder<GifDrawable> scGif(RequestBuilder<GifDrawable> requestBuilder) {
        return requestBuilder
                .transition(new DrawableTransitionOptions())
                .apply(decodeTypeOf(GifDrawable.class).lock());
}


方法名为什么叫scGif,而不是asGif,因为GlideRequests中已经有一个asGif方法。


       2.将在GlideRequests生成一个如下所示的方法:


1.public class GlideRequests extends RequestManager {
  public GlideRequest<GifDrawable> scGif() {
    return (GlideRequest<GifDrawable>) MyGlideExtension.scGif(this.as(GifDrawable.class));
  }
  ...
}


3.使用生成的GlideApp类来调用您的自定义类型(选择资源类型):


        GlideApp.with(this)
                .scGif()
                .load(uri)
                .applyBlurHeadScc(150)
                .addListener(new RequestListener<GifDrawable>() {
                    @Override
                    public boolean onLoadFailed(GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
                        return false;
                    }
                    @Override
                    public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) {
                        return false;
                    }
                })
                .into(agb.ivCirclecrop);


RequestListener 返回的类型为你scGif设置的GifDrawable 相对应。


submit同步获取图片资源


FutureTarget<Bitmap> target= GlideApp.with(this)
                .asBitmap()
                .load(uri)
                .applyBlurHeadScc(150)
                .submit();
        //因target.get()是同步请求
        //所以用线程转异步请求
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Bitmap bitmap = target.get();//同步请求
                    //子线程切主线程更新UI
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            agb.ivOptions.setImageBitmap(bitmap);
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();


微信图片_20220521212838.png


效果跟之前的一样一样的。 这个功能就是有特殊需求时对获取的图片进行特殊处理。


Application Options(选项)


       Glide 允许应用通过 AppGlideModule 实现来完全控制 Glide 的内存和磁盘缓存使用。Glide 试图提供对大部分应用程序合理的默认选项,但对于部分应用,可能就需要定制这些值。在你做任何改变时,请注意测量其结果,避免出现性能的倒退。


Memory cache(内存缓存)


       默认情况下,Glide使用 LruResourceCache ,这是 MemoryCache 接口的一个缺省实现,使用固定大小的内存和 LRU 算法。LruResourceCache 的大小由 Glide 的 MemorySizeCalculator 类来决定,这个类主要关注设备的内存类型,设备 RAM 大小,以及屏幕分辨率。


       1.自定义 MemoryCache 的大小,具体是在它们的 AppGlideModule 中使用 applyOptions(Context, GlideBuilder) 方法配置 MemorySizeCalculator:


@GlideModule
public class MyGlideModule 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()));
    }
}


2.直接覆盖缓存大小:


@GlideModule
public class MyGlideModule extends AppGlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        int memoryCacheSizeBytes = 1024 * 1024 * 10; // 10mb
        builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));
    }
}


3.提供自己的 MemoryCache 实现:


@GlideModule
public class MyGlideModule extends AppGlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setMemoryCache(new MyMemoryCacheImpl());
    }
}


Disk Cache(磁盘缓存)


       Glide 使用 DiskLruCacheWrapper 作为默认的磁盘缓存。 DiskLruCacheWrapper 是一个使用 LRU 算法的固定大小的磁盘缓存。默认磁盘大小为 250 MB ,位置是在应用的 缓存文件夹 中的一个 特定目录


      1.如果显示的媒体是公开的(从未经身份验证的网站、搜索引擎等获取),则应用程序可以将位置更改为外部存储:


@GlideModule
public class MyGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
  }
}


2.无论使用内部或外部磁盘缓存,应用程序都可以改变磁盘缓存的大小:


@GlideModule
public class MyGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int diskCacheSizeBytes = 1024 * 1024 * 100; // 100 MB
    builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskCacheSizeBytes));
  }
}


  3.应用程序还可以改变缓存文件夹在外存或内存上的名字:


@GlideModule
public class MyGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int diskCacheSizeBytes = 1024 * 1024 * 100; // 100 MB
    builder.setDiskCache(
        new InternalCacheDiskCacheFactory(context, "cacheFolderName", diskCacheSizeBytes));
  }
}


  4.应用程序还可以自行选择 DiskCache 接口的实现,并提供自己的 DiskCache.Factory 来创建缓存。Glide 使用一个工厂接口来在后台线程中打开 磁盘缓存 ,这样方便缓存做诸如检查路径存在性等的IO操作而不用触发 严格模式 。


@GlideModule
public class MyGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDiskCache(new DiskCache.Factory() {
        @Override
        public DiskCache build() {
          return new MyCustomDiskCache();
        }
    });
  }
}


Bitmap pool(位图池)


       Glide 使用 LruBitmapPool 作为默认的 BitmapPool 。LruBitmapPool 是一个内存中的固定大小的 BitmapPool,使用 LRU 算法清理。默认大小基于设备的分辨率和密度,同时也考虑内存类和 isLowRamDevice 的返回值。具体的计算通过 Glide 的 MemorySizeCalculator 来完成,与 Glide 的 MemoryCache 的大小检测方法相似。


      1.可以在它们的 AppGlideModule 中定制 BitmapPool 的尺寸,使用 applyOptions(Context, GlideBuilder) 方法并配置 MemorySizeCalculator:


@GlideModule
public class MyGlideModule extends AppGlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context)
                .setBitmapPoolScreens(3)
                .build();
        builder.setBitmapPool(new LruBitmapPool(calculator.getBitmapPoolSize()));
    }
}


  2.直接复写这个池的大小:


@GlideModule
public class MyGlideModule extends AppGlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        int bitmapPoolSizeBytes = 1024 * 1024 * 30; // 30mb
        builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));
    }
}


3.提供自己的BitmapPool实现:


@GlideModule
public class MyGlideModule extends AppGlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setBitmapPool(new MyBitmapPoolImpl());
    }
}


配置缓存


磁盘缓存策略(Disk Cache Strategy)


       DiskCacheStrategy 可被 diskCacheStrategy 方法应用到每一个单独的请求。 目前支持的策略允许你阻止加载过程使用或写入磁盘缓存,选择性地仅缓存无修改的原生数据,或仅缓存变换过的缩略图,或是兼而有之。


指定 DiskCacheStrategy 非常容易:


    Glide.with(this)
            .load(uri)
            .diskCacheStrategy(DiskCacheStrategy.ALL)
            .into(imageView);


一个 diskCacheStrategy() 方法就可以调整他的硬盘缓存策略。其中可以传入的参数有五种:


  • DiskCacheStrategy.AUTOMATIC :表示对于本地数据,AUTOMATIC 策略则会仅存储变换过的缩略图;远程数据(Uri下载)仅会存储未被你的加载过程修改过(比如:变换、裁剪)的原始数据(默认选项)。


  • DiskCacheStrategy.NONE: 表示不缓存任何内容。


  • DiskCacheStrategy.DATA: 表示只缓存原始图片。


  • DiskCacheStrategy.RESULT: 表示只缓存转换过后的图片。


  • DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。


仅从缓存加载图片


       某些情形下,你可能希望只要图片不在缓存中则加载直接失败(省流量?)。如果要完成这个目标,你可以在单个请求的基础上使用 onlyRetrieveFromCache 方法:


Glide.with(this)
        .load(uri)
        .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
        .onlyRetrieveFromCache(true);
        .into(imageView);


如果图片在内存缓存或在磁盘缓存中,它会被展示出来。否则只要这个选项被设置为 true ,这次加载会视同失败。


跳过缓存


       如果你想确保一个特定的请求跳过磁盘和/或内存缓存(比如:图片验证码),Glide 也提供了一些替代方案。


       仅跳过内存缓存,请使用 skipMemoryCache() :


Glide.with(fragment)
  .load(url)
  .skipMemoryCache(true)
  .into(imageView);


       仅跳过磁盘缓存,请使用 DiskCacheStrategy.NONE :


Glide.with(fragment)
  .load(url)
  .diskCacheStrategy(DiskCacheStrategy.NONE)
  .into(imageView);


       以上两个选项可以同时使用:


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


       虽然提供了这些办法让你跳过缓存,但你通常应该不会想这么做。从缓存中加载一个图片,要比拉取-解码-转换成一张新图片的完整流程快得多。


清理磁盘缓存


       要尝试清理所有磁盘缓存条目,你可以使用 clearDiskCache。


new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 必须在子线程上调用此方法。
                    Glide.get(AppGlobalUtils.getApplication()).clearDiskCache();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();


相关资源


Glide 缓存机制及源码(二)


Glide git传送门


Glide中文文档


glide-transformations传送门


 glide-transformations:一个 Android 转换库,为Glide提供各种图像转换。下面是效果图:


微信图片_20220521213955.png


以上内容看完Glide的基本使用肯定是没问题的,如有问题,烦请指正。想要了解更多可以通过下面的传送门自行查看。后面会有一篇文章专门来介绍Glide缓存机制,嘿嘿嘿。大家一起加油。



相关文章
|
数据处理 Android开发
关于安卓glide加载显示进度
安卓glide加载显示进度
388 0
|
1月前
|
Java Android开发
Android面试题经典之Glide取消加载以及线程池优化
Glide通过生命周期管理在`onStop`时暂停请求,`onDestroy`时取消请求,减少资源浪费。在`EngineJob`和`DecodeJob`中使用`cancel`方法标记任务并中断数据获取。当网络请求被取消时,`HttpUrlFetcher`的`cancel`方法设置标志,之后的数据获取会返回`null`,中断加载流程。Glide还使用定制的线程池,如AnimationExecutor、diskCacheExecutor、sourceExecutor和newUnlimitedSourceExecutor,其中某些禁止网络访问,并根据CPU核心数动态调整线程数。
77 2
|
1月前
|
缓存 编解码 安全
Android经典面试题之Glide的缓存大揭秘
Glide缓存机制包括内存和硬盘缓存。内存缓存使用弱引用的ActiveResources和LRU策略,硬盘缓存利用DiskLruCache。Engine.load方法首先尝试从内存和弱引用池加载,然后从LRU缓存中加载图片,增加引用计数并移出LRU。若缓存未命中,启动新任务或加入现有任务。内存大小根据设备内存动态计算,限制在0.4以下。DiskLruCache使用自定义读写锁,保证并发安全,写操作通过锁池管理,确保高效。
29 0
|
3月前
|
Android开发
Android中Glide加载Https图片失败的解决方案
Android中Glide加载Https图片失败的解决方案
199 1
|
3月前
|
Android开发
Android实现圆形图像的两种方法(Glide和Picasso)
Android实现圆形图像的两种方法(Glide和Picasso)
74 1
|
3月前
|
API Android开发
[Android]图片加载库Glide
[Android]图片加载库Glide
80 0
|
3月前
|
XML 缓存 Java
Android App开发之利用Glide实现图片的三级缓存Cache讲解及实战(附源码 超详细必看 简单易懂)
Android App开发之利用Glide实现图片的三级缓存Cache讲解及实战(附源码 超详细必看 简单易懂)
244 0
|
3月前
|
XML Java Android开发
Android App开发中使用Glide加载网络图片讲解及实战(附源码 简单易懂)
Android App开发中使用Glide加载网络图片讲解及实战(附源码 简单易懂)
188 0
|
3月前
|
XML Java Android开发
Android Studio App开发之利用图片加载框架Glide实现刷新验证码功能(附源码 简单易懂)
Android Studio App开发之利用图片加载框架Glide实现刷新验证码功能(附源码 简单易懂)
43 0
|
Java Android开发
Android万能的图片加载框架(Glide、Fresco、Picasso)
Android万能的图片加载框架(Glide、Fresco、Picasso)