Glide 4.0梳理
现有图片框架介绍
Universal-Image-Loader(UIL)
- GitHub: https://github.com/nostra13/Android-Universal-Image-Loader
- 最早的图片加载框架
- 去年9月份停止项目维护
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
- GitHub: https://github.com/bumptech/glide
- Google主导
- 无需初始化
- 可以加载Gif和WebP格式,支持视频缩略图
总结
- 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没有生成
- 检查一下配置文件
- 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
:要求DrawableBitmapTransitionOptions
:要求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);
通过TransitionOptions
用ViewPropertyTransition.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全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论