Glide4.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个参数

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

加载其他来源的图片

1、资源文件

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

2、本地图片

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

3、通过Uri方式

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

占位符

1
2
3
4
5
6
7
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的子类来配置。

1
2
@GlideModule
public final class MyAppGlideModule extends AppGlideModule {}

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

1
2
3
4
GlideApp
.with(fragment)
.load(myUrl)
.into(imageView)

如果GlideApp没有生成

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

选择项(RequestOptions)

基本的使用

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

主要功能

(1)占位符

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

(2)转换

转换成圆角图片

1
requestOptions.transform(new RoundedCorners(20));

(3)缓存策略

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

1
requestOptions.skipMemoryCache(false);

(4)磁盘缓存策略

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

(5)图片设置

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

(6)其他

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

转换(Transform)

图片预处理

1
2
3
4
requestOptions.centerInside();
requestOptions.centerCrop();
requestOptions.circleCrop();
requestOptions.fitCenter();

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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);
}
}

使用

1
2
3
4
5
6
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像素图。

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 不显示到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
1
2
3
GlideApp.with(this).asBitmap().load(url)
.transition(BitmapTransitionOptions.withCrossFade())
.into(imageView6);

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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>
1
2
3
4
5
6
BitmapTransitionOptions bitmapTransitionOptions =  new BitmapTransitionOptions();
bitmapTransitionOptions.transition(R.anim.glide_animate);

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

通过TransitionOptionsViewPropertyTransition.Animator自定义动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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();
}
}
1
2
3
4
5
6
BitmapTransitionOptions bitmapTransitionOptions =  new BitmapTransitionOptions();
bitmapTransitionOptions.transition(new MyAnimator());

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

自定义GlideModule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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;
}
}

全局配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Photo {

private String url;


public String getUrl() {
return url;
}

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

}

PhotoModelLoader.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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;
}

}

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

1
2
3
4
5
@Override
public void registerComponents(Context context, Glide glide, Registry registry) {

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

其他

设置优先级

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

设置缩略图

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

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

1
GlideApp.get(this).clearMemory();

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

1
GlideApp.get(this).clearDiskCache();

Recycle的加载优化

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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梳理

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :