Glide 4.0梳理

现有图片框架介绍

Universal-Image-Loader(UIL)

Picasso

  • GitHub: https://github.com/square/picasso
  • Square 公司的作品,理论上和Square其他库结合的会相对较好
  • 只有网络库实现的缓存,可以通过头文件的Cache-Control 和 Expired控制图片是否过期

Fresco

  • GitHub: https://github.com/facebook/fresco
  • Facebook公司的作品
  • 3级缓存设计
  • 在android 5.0以下图片不存储在Java heap,减少OOM
  • JPEG图片可以在native进行resize
  • 可以加载Gif和WebP格式,支持视频缩略图
  • 体积过于庞大(以M来计算)

Glide

总结

  • UIL和Picasso不支持Gif,这个是个硬伤。
  • Fresco体积过于庞大,除非是图片处理主导的应用,否则无法凸显它的价值。
  • Glide可以完成Picasso的功能,而且体积也比较小。所以一般项目首选。

Glide 4.0基本用法

1、无需初始化
2、使用流接口
3、完整的请求需要3个参数

Glide.with(this) //获取上下文环境
     .load(url) //图片地址
     .into(imageView1); //图片显示的地方

加载其他来源的图片

1、资源文件

Glide.with(this).load(R.drawable.hsk1).into(imageView1);

2、本地图片

File file = new File("图片地址");
Glide.with(this).load(file).into(imageView1);

3、通过Uri方式

Uri uri = Uri.parse(url);
Glide.with(this).load(uri).into(imageView1);

占位符

GlideApp
  .with(this)
  .load(url)
  .placeholder(R.drawable.image320)  //加载的时候占位
  .error(new ColorDrawable(Color.BLUE))  //请求资源失败的时候
  .fallback(new ColorDrawable(Color.CYAN))  //当请求内容为null的时候显示
  .into(imageView2);

GlideApp

在4.0中不用像3.X需要在AndroidManifest.xml配置GlideModule,而是通过注解继承AppGlideModule的子类来配置。

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {}

使用的时候用GlideApp.with()代替Glide.with()

GlideApp
  .with(fragment)
  .load(myUrl)
  .into(imageView)

如果GlideApp没有生成

  1. 检查一下配置文件
  2. clean工程,build工程

选择项(RequestOptions)

基本的使用

RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(R.drawable.image320);
GlideApp.with(this).load(url)
        .apply(requestOptions)
        .into(imageView3);

主要功能

(1)占位符

requestOptions.placeholder(R.drawable.image320);
requestOptions.error(new ColorDrawable(Color.BLUE));
requestOptions.fallback(new ColorDrawable(Color.CYAN));

(2)转换

转换成圆角图片

requestOptions.transform(new RoundedCorners(20));

(3)缓存策略

跳过内存缓存,这个默认就是false。如果不需要就设置为true来确保不会缓存到内存中

requestOptions.skipMemoryCache(false);

(4)磁盘缓存策略

requestOptions.diskCacheStrategy(DiskCacheStrategy.ALL);
DiskCacheStrategy.ALL:缓存所有图片
DiskCacheStrategy.NONE:不缓存任何图片
DiskCacheStrategy.DATA:缓存原始数据
DiskCacheStrategy.RESOURCE:缓存转换后的数据
DiskCacheStrategy.AUTOMATIC:自动选择存储数据

(5)图片设置

requestOptions.encodeFormat(Bitmap.CompressFormat.WEBP);  //图片格式
requestOptions.encodeQuality(90);  //图片质量
requestOptions.format(DecodeFormat.PREFER_RGB_565);  //图片模式
requestOptions.override(40,40);  //图片限制大小

(6)其他

requestOptions.dontTransform();  //禁止转换
requestOptions.dontAnimate();  //禁止动画化

转换(Transform)

图片预处理

requestOptions.centerInside();
requestOptions.centerCrop();
requestOptions.circleCrop();
requestOptions.fitCenter();

如果当没有调用transform方法并且允许转变的情况下会进行以下处理:

public Target<TranscodeType> into(ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    if (!requestOptions.isTransformationSet()
        && requestOptions.isTransformationAllowed()
        && view.getScaleType() != null) {
      if (requestOptions.isLocked()) {
        requestOptions = requestOptions.clone();
      }
      switch (view.getScaleType()) {
        case CENTER_CROP:
          requestOptions.optionalCenterCrop();
          break;
        case CENTER_INSIDE:
          requestOptions.optionalCenterInside();
          break;
        case FIT_CENTER:
        case FIT_START:
        case FIT_END:
          requestOptions.optionalFitCenter();
          break;
        case FIT_XY:
          requestOptions.optionalCenterInside();
          break;
        case CENTER:
        case MATRIX:
        default:
          // Do nothing.
      }
    }
}

自定义模糊转换

MyBlurTransformation.class

public class MyBlurTransformation extends BitmapTransformation {

    private static final String ID = "gift.witch.glide.MyBlurTransformation";
    private static final byte[] ID_BYTES = ID.getBytes(CHARSET);

    private static int MAX_RADIUS = 25;
    private static int DEFAULT_DOWN_SAMPLING = 1;

    private int mRadius;
    private int mSampling;
    private Context mContext;

    public MyBlurTransformation(Context context) {
        init(context, MAX_RADIUS, DEFAULT_DOWN_SAMPLING);
    }

    public MyBlurTransformation(Context context, BitmapPool pool) {
        init(context, MAX_RADIUS, DEFAULT_DOWN_SAMPLING);
    }

    public MyBlurTransformation(Context context, BitmapPool pool, int radius) {
        init(context, radius, DEFAULT_DOWN_SAMPLING);
    }

    public MyBlurTransformation(Context context, int radius) {
        init(context, radius, DEFAULT_DOWN_SAMPLING);
    }

    public MyBlurTransformation(Context context, int radius, int sampling) {
        init(context, radius, sampling);
    }

    private void init(Context context, int radius, int sampling) {
        mContext = context.getApplicationContext();
        mRadius = radius;
        mSampling = sampling;
    }

    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {

        Bitmap source = getAlphaSafeBitmap(pool, toTransform);

        int width = source.getWidth();
        int height = source.getHeight();
        int scaledWidth = width / mSampling;
        int scaledHeight = height / mSampling;

        Bitmap bitmap = pool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
        if (bitmap == null) {
            bitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(bitmap);
        canvas.scale(1 / (float) mSampling, 1 / (float) mSampling);
        Paint paint = new Paint();
        paint.setFlags(Paint.FILTER_BITMAP_FLAG);
        canvas.drawBitmap(source, 0, 0, paint);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            try {
                bitmap = RSBlur.blur(mContext, bitmap, mRadius);
            } catch (RSRuntimeException e) {
                bitmap = FastBlur.blur(bitmap, mRadius, true);
            }
        } else {
            bitmap = FastBlur.blur(bitmap, mRadius, true);
        }

        if (!source.equals(toTransform)) {
            pool.put(source);
        }

        return bitmap;
    }

    private Bitmap getAlphaSafeBitmap(@NonNull BitmapPool pool,
                                             @NonNull Bitmap maybeAlphaSafe) {
        if (Bitmap.Config.ARGB_8888.equals(maybeAlphaSafe.getConfig())) {
            return maybeAlphaSafe;
        }

        Bitmap argbBitmap = pool.get(maybeAlphaSafe.getWidth(), maybeAlphaSafe.getHeight(),
                Bitmap.Config.ARGB_8888);
        new Canvas(argbBitmap).drawBitmap(maybeAlphaSafe, 0 /*left*/, 0 /*top*/, null /*pain*/);

        // We now own this Bitmap. It's our responsibility to replace it in the pool outside this method
        // when we're finished with it.
        return argbBitmap;
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        messageDigest.update(ID_BYTES);
        byte[] radiusData = ByteBuffer.allocate(4).putInt(mRadius).array();
        messageDigest.update(radiusData);
    }
}

使用

RequestOptions requestOptions1 = new RequestOptions();
requestOptions1.transform(new MyBlurTransformation(this));
GlideApp.with(this)
        .load(url)
        .apply(requestOptions1)
        .into(imageView7);

目标(Target)

  • BaseTarget<Z> (implements Target<R>)
    • SimpleTarget<Z>
      • AppWidgetTarget
      • NotificationTarget
      • PreloadTarget<Z>
    • ViewTarget<T,Z>
      • ImageViewTarget<Z>
      • BitmapImageViewTarget
      • DrawableImageViewTarget
      • GlideDrawableImageViewTarget
    • Drawable
      • GlideDrawable (implements Animatable)
      • SquaringDrawable
  • ImageViewTargetFactory

这里加载到的目标是simpleTarget,等加载完会返回resource像素图。

/**
 * 不显示到ImageView里
 */
SimpleTarget<Bitmap> simpleTarget = new SimpleTarget<Bitmap>(50,50) {

    @Override
    public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
        imageView4.setImageBitmap(resource);
    }
};

GlideApp.with(this).asBitmap().load(url)
        .into(simpleTarget);

过渡(Transition)

有三种类型

  • GenericTransitionOptions:通用类型
  • DrawableTransitionOptions:要求Drawable
  • BitmapTransitionOptions:要求Bitmap
GlideApp.with(this).asBitmap().load(url)
        .transition(BitmapTransitionOptions.withCrossFade())
        .into(imageView6);

通过TransitionOptions用动画资源文件自定义动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="10000">
    <alpha
        android:fromAlpha="0.5"
        android:toAlpha="1.0" />
    <scale
        android:fromXScale="0.5"
        android:fromYScale="0.5"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.0"
        android:toYScale="1.0" />
</set>
BitmapTransitionOptions bitmapTransitionOptions =  new BitmapTransitionOptions();
bitmapTransitionOptions.transition(R.anim.glide_animate);

GlideApp.with(this).asBitmap().load(url)
                .transition(bitmapTransitionOptions)
                .into(imageView6);

通过TransitionOptionsViewPropertyTransition.Animator自定义动画

public class MyAnimator implements ViewPropertyTransition.Animator {

    @Override
    public void animate(View view) {
        final View finalView = view;
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.setDuration(10000);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                finalView.setScaleX((float) (0.5 + 0.5 * value));
                finalView.setScaleY((float) (0.5 + 0.5 * value));
                finalView.setRotation(180* value);
                finalView.setAlpha(value);
            }
        });
        valueAnimator.start();
    }
}
BitmapTransitionOptions bitmapTransitionOptions =  new BitmapTransitionOptions();
bitmapTransitionOptions.transition(new MyAnimator());

GlideApp.with(this).asBitmap().load(url)
                .transition(bitmapTransitionOptions)
                .into(imageView6);

自定义GlideModule

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {
    //注册自定义组件
    @Override
    public void registerComponents(Context context, Glide glide, Registry registry) {
    }

    //全局配置Glide
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
    }

    // 避免二次加载
    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }
}

全局配置

@Override
public void applyOptions(Context context, GlideBuilder builder) {
    // Default empty impl.
    //设置Bitmap的缓存池
    builder.setBitmapPool(new LruBitmapPool(30));

    //设置内存缓存
    builder.setMemoryCache(new LruResourceCache(30));

    //设置磁盘缓存
    builder.setDiskCache(new InternalCacheDiskCacheFactory(context));

    //设置读取不在缓存中资源的线程
    builder.setResizeExecutor(GlideExecutor.newSourceExecutor());

    //设置读取磁盘缓存中资源的线程
    builder.setDiskCacheExecutor(GlideExecutor.newDiskCacheExecutor());

    //设置日志级别
    builder.setLogLevel(Log.VERBOSE);

    //设置全局选项
    RequestOptions requestOptions = new RequestOptions();
    requestOptions.format(DecodeFormat.PREFER_RGB_565);
    builder.setDefaultRequestOptions(requestOptions);
}

自定义组件

Photo.class

public class Photo {

    private String url;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

}

PhotoModelLoader.class

public class PhotoModelLoader extends BaseGlideUrlLoader<Photo> {

    public static class Factory implements ModelLoaderFactory<Photo, InputStream> {

        private final ModelCache<Photo, GlideUrl> modelCache = new ModelCache<Photo, GlideUrl>(500);

        @Override
        public ModelLoader<Photo, InputStream> build(MultiModelLoaderFactory multiFactory) {
            return new PhotoModelLoader(multiFactory.build(GlideUrl.class, InputStream.class),
                    modelCache);
        }

        @Override
        public void teardown() {
        }
    }

    protected PhotoModelLoader(ModelLoader<GlideUrl, InputStream> concreteLoader) {
        super(concreteLoader);
    }

    protected PhotoModelLoader(ModelLoader<GlideUrl, InputStream> concreteLoader, @Nullable ModelCache<Photo, GlideUrl> modelCache) {
        super(concreteLoader, modelCache);
    }

    @Override
    protected String getUrl(Photo photo, int width, int height, Options options) {
        return photo.getUrl();
    }

    @Override
    public boolean handles(Photo photo) {
        return true;
    }

}

使用时,注册组件和模块加载器

@Override
public void registerComponents(Context context, Glide glide, Registry registry) {

    registry.append(Photo.class, InputStream.class, new PhotoModelLoader.Factory());
}

其他

设置优先级

GlideApp.with(this).load(url).priority(Priority.HIGH)

设置缩略图

GlideApp.with(this).load(url).thumbnail(0.3f);

清除内存缓存(需要在UI线程里调用)

GlideApp.get(this).clearMemory();

清除磁盘缓存(需要在子线程里调用)

GlideApp.get(this).clearDiskCache();

Recycle的加载优化

只在拖动和静止时加载,自动滑动时不加载

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        switch (newState) {
            case RecyclerView.SCROLL_STATE_DRAGGING:
                Glide.with(MainActivity.this).resumeRequests();  //加载
                break;
            case RecyclerView.SCROLL_STATE_SETTLING:
                Glide.with(MainActivity.this).pauseRequests();  //暂停加载
                break;
            case RecyclerView.SCROLL_STATE_IDLE:
                Glide.with(MainActivity.this).resumeRequests();  //加载
                break;
        }
    }
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
    }
});

本文转载至:Glide4.0梳理

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/02/26/glide-4-sorting/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Glide 4.0梳理
现有图片框架介绍 Universal-Image-Loader(UIL) GitHub: https://github.com/nostra13/Android-Universal-Image-Loader 最早的图片加载框架 去年9月份停止项……
<<上一篇
下一篇>>
文章目录
关闭
目 录