一、起因
我们在项目中需要经常使用RecyclerView,但是刷新的时候闪烁确不经常见。我在做项目的过程中,使用Gilde库进行加载图片,根据产品设计,列表中的图片是需要圆角的,并且有些地方是需要局部圆角的,于是我在网上找了一个RoundCornersTransformation的工具类,可以对部分地方进行圆角绘制,对于单张图片的加载是没有问题的,但是后来使用RecyclerView进行notifyDataSetChanged刷新时,问题就悄无声息的发生了。天啊!这闪烁的节奏感,赶紧嗨起来!
二、经过
我第一时间对所写的代码进行了地毯式的排查,首先怀疑到了RecyclerView上面了,对于网上说的是众说纷纭:
①自定义DefaultItemAnimator:这里就不细说了,详见:
RecyclerView刷新闪烁问题_u013346208的博客-CSDN博客_recyclerview刷新数据闪烁
②还有各种设置例如:
((SimpleItemAnimator)RecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
Adapter.setHasStableIds(false);
RecyclerView.getItemAnimator().setChangeDuration(0);
经过如上的排查,哎嘿,你猜怎么着,压根就没有管用。
于是我就赶紧换方案,改用排除法,如果是RecyclerView导致的图片闪烁,那么加载资源文件里面的图片也应该是列表刷新闪烁的,但是经过多次实验排查,并非想像中的那样,一点也没有闪烁。这时,我就感到此时离真相已经不远了。。。
三、结果
既然已经进入了这个阶段,我就怀疑到了RoundCornersTransformation工具类。经过查看官方文档,终于找到了真相。
必须得实现如下的三个函数:
equals(Object o)
hashCode()
updateDiskCacheKey(MessageDigest messageDigest)
这三个函数实现后,终于不闪烁了,问题解决了,希望让更多的人能从此脱坑,走上人生巅峰。
public class RoundCornersTransformation implements Transformation<Bitmap> {
private final String ID = "com. bumptech.glide.transformations.FillSpace";
private final byte[] ID_ByTES = ID.getBytes(CHARSET);
private BitmapPool mBitmapPool;
private int mRadius;
private int mDiameter;
private CornerType mCornerType = CornerType.ALL;
public RoundCornersTransformation(Context context, int radius, CornerType type) {
mBitmapPool = Glide.get(context).getBitmapPool();
mCornerType = type;
mRadius = radius;
mDiameter = 2 * mRadius;
}
public enum CornerType {
/**
* 所有角
*/
ALL,
/**
* 左上
*/
LEFT_TOP,
/**
* 左下
*/
LEFT_BOTTOM,
/**
* 右上
*/
RIGHT_TOP,
/**
* 右下
*/
RIGHT_BOTTOM,
/**
* 左侧
*/
LEFT,
/**
* 右侧
*/
RIGHT,
/**
* 下侧
*/
BOTTOM,
/**
* 上侧
*/
TOP,
}
@Override
public Resource<Bitmap> transform(@NonNull Context context, @NonNull Resource<Bitmap> resource, int outWidth, int outHeight) {
Bitmap source = resource.get();
int width = source.getWidth();
int height = source.getHeight();
Bitmap bitmap = mBitmapPool.get(width, height, Bitmap.Config.ARGB_8888);
if (bitmap == null) {
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
drawRoundRect(canvas, paint, width, height);
return BitmapResource.obtain(bitmap, mBitmapPool);
}
private void drawRoundRect(Canvas canvas, Paint paint, float width, float height) {
switch (mCornerType) {
case LEFT_TOP:
drawLeftTopCorner(canvas, paint, width, height);
break;
case LEFT_BOTTOM:
drawLeftBottomCorner(canvas, paint, width, height);
break;
case RIGHT_TOP:
drawRightTopCorner(canvas, paint, width, height);
break;
case RIGHT_BOTTOM:
drawRightBottomCorner(canvas, paint, width, height);
break;
case LEFT:
drawLeftCorner(canvas, paint, width, height);
break;
case RIGHT:
drawRightCorner(canvas, paint, width, height);
break;
case BOTTOM:
drawBottomCorner(canvas, paint, width, height);
break;
case TOP:
drawTopCorner(canvas, paint, width, height);
break;
case ALL:
default:
canvas.drawRoundRect(new RectF(0, 0, width, height), mRadius, mRadius, paint);
break;
}
}
/**
* 画左上角
*/
private void drawLeftTopCorner(Canvas canvas, Paint paint, float width, float height) {
canvas.drawRect(new RectF(mRadius, 0, width, height), paint);
canvas.drawRect(new RectF(0, mRadius, mRadius, height), paint);
canvas.drawArc(new RectF(0, 0, mDiameter, mDiameter), 180, 90, true, paint);
}
/**
* 画左下角
*/
private void drawLeftBottomCorner(Canvas canvas, Paint paint, float width, float height) {
canvas.drawRect(new RectF(0, 0, width, height - mRadius), paint);
canvas.drawRect(new RectF(mRadius, height - mRadius, width, height), paint);
canvas.drawArc(new RectF(0, height - mDiameter, mDiameter, height), 90, 90, true, paint);
}
/**
* 画右上角
*/
private void drawRightTopCorner(Canvas canvas, Paint paint, float width, float height) {
canvas.drawRect(new RectF(0, 0, width - mRadius, height), paint);
canvas.drawRect(new RectF(width - mRadius, mRadius, width, height), paint);
canvas.drawArc(new RectF(width - mDiameter, 0, width, mDiameter), 270, 90, true, paint);
}
/**
* 画右下角
*/
private void drawRightBottomCorner(Canvas canvas, Paint paint, float width, float height) {
canvas.drawRect(new RectF(0, 0, width, height - mRadius), paint);
canvas.drawRect(new RectF(0, height - mRadius, width - mRadius, height), paint);
canvas.drawArc(new RectF(width - mDiameter, height - mDiameter, width, height), 0, 90, true, paint);
}
/**
* 画左 角
*/
private void drawLeftCorner(Canvas canvas, Paint paint, float width, float height) {
canvas.drawRect(new RectF(mRadius, 0, width, height), paint);
canvas.drawRect(new RectF(0, mRadius, mRadius, height - mRadius), paint);
canvas.drawArc(new RectF(0, 0, mDiameter, mDiameter), 180, 90, true, paint);
canvas.drawArc(new RectF(0, height - mDiameter, mDiameter, height), 90, 90, true, paint);
}
/**
* 画右角
*/
private void drawRightCorner(Canvas canvas, Paint paint, float width, float height) {
canvas.drawRect(new RectF(0, 0, width - mRadius, height), paint);
canvas.drawRect(new RectF(width - mRadius, mRadius, width, height - mRadius), paint);
canvas.drawArc(new RectF(width - mDiameter, 0, width, mDiameter), 270, 90, true, paint);
canvas.drawArc(new RectF(width - mDiameter, height - mDiameter, width, height), 0, 90, true, paint);
}
/**
* 画上 角
*/
private void drawTopCorner(Canvas canvas, Paint paint, float width, float height) {
canvas.drawRect(new RectF(0, mRadius, width, height), paint);
canvas.drawRect(new RectF(mRadius, 0, width - mRadius, mRadius), paint);
canvas.drawArc(new RectF(0, 0, mDiameter, mDiameter), 180, 90, true, paint);
canvas.drawArc(new RectF(width - mDiameter, 0, width, mDiameter), 270, 90, true, paint);
}
/**
* 画下 角
*/
private void drawBottomCorner(Canvas canvas, Paint paint, float width, float height) {
canvas.drawRect(new RectF(0, 0, width, height - mRadius), paint);
canvas.drawRect(new RectF(mRadius, height - mRadius, width - mRadius, height), paint);
canvas.drawArc(new RectF(0, height - mDiameter, mDiameter, height), 90, 90, true, paint);
canvas.drawArc(new RectF(width - mDiameter, height - mDiameter, width, height), 0, 90, true, paint);
}
@Override
public boolean equals(Object o) {
if (o instanceof RoundCornersTransformation) {
RoundCornersTransformation other = (RoundCornersTransformation) o;
return mRadius == other.mRadius;
}
return false;
}
@Override
public int hashCode() {
return Util.hashCode(ID.hashCode(), Util.hashCode(mRadius));
}
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
messageDigest.update(ID_ByTES);
byte[] radiusData = ByteBuffer.allocate(4).putInt((int) mRadius).array();
messageDigest.update(radiusData);
}
}
补充一下:在Glide中不要忘了加上skipMemoryCache(false)