Android glide使用过程中遇到的坑(进阶篇)

之前有写过一篇关于glide的基本使用和相关配置,这篇就给大家分享一下glide在项目中通常会遇到的一些坑及解决方法

目前glide版本已经升级到了4.7.1,所以之前在用3.x版本的朋友,升级到最新版本的Api会有一些不一样的地方,详细不同地方可以参考官方介绍 https://muyangmin.github.io/glide-docs-cn/doc/migrating.html

最新版本配置环境:

implementation 'com.github.bumptech.glide:glide:4.7.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'

下面就来看看使用过程中遇到的坑,以下代码都是使用glide 4.7.1的api ,大家注意下。

当后台把用户的头像用地址前缀加用户ID拼接设计成时,往往修改头像后,再用Glide加载会发现头像还是之前的头像,原因很简单,是由于Glide默认加载了缓存的图片,所以导致更改之后地址没变还是加载之前的图片,如需要不加载缓存图片,可以使用如下代码:

    public static void display(ImageView imageView, String url) {
        if (imageView == null) return;
        Glide.with(imageView.getContext())
                .load(url)
                .apply(new RequestOptions()
                .dontAnimate()
                .skipMemoryCache(true)
                .diskCacheStrategy(DiskCacheStrategy.NONE))
                .into(imageView);
    }

设置圆角图片时,正好布局文件中用到了自定义圆角控件,这时应该这样处理代码如下:

    /**
     * 设置圆角
     * @param imageView
     * @param path
     * @param dp  圆角度数 90dp宽高一致时为圆形
     */
    public static void displayRound(ImageView imageView, String url, int dp) {
        RequestOptions options = new RequestOptions()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .transforms(new CenterCrop(), new GlideRoundTransform(dp));
        Glide.with(imageView.getContext()).load(url)
                .apply(options)
                .transition(new DrawableTransitionOptions().crossFade())
                .into(imageView);
    }

    public class GlideRoundTransform extends BitmapTransformation {

        private static float radius = 0f;

        public GlideRoundTransform() {
            this(4);
        }

        public GlideRoundTransform(int dp) {
            radius = Resources.getSystem().getDisplayMetrics().density * dp;
        }

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

        private static Bitmap roundCrop(BitmapPool pool, Bitmap source) {
            if (source == null) return null;
            Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
            if (result == null) {
                result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
            }
            Canvas canvas = new Canvas(result);
            Paint paint = new Paint();
            paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
            paint.setAntiAlias(true);
            RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
            canvas.drawRoundRect(rectF, radius, radius, paint);
            return result;
        }


        public String getId() {
            return getClass().getName() + Math.round(radius);
        }

        @Override
        public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {

        }
    }

加载大图时会有可能出现OOM,可以控制高宽尺寸来处理,高宽设置一个合理的尺寸即可

    public static void display(ImageView imageView, String url) {
        if (imageView == null) return;
        Glide.with(imageView.getContext())
                .load(url)
                .apply(new RequestOptions()
                .override(180, 180))
                .into(imageView);
    }

第一次加载图片可能会出现拉伸变形,设置.dontAnimate()取消动画即可解决

    public static void display(ImageView imageView, String url) {
        if (imageView == null) return;
        Glide.with(imageView.getContext())
                .load(url)
                .apply(new RequestOptions().dontAnimate())
                .into(imageView);
    }

当占位图的ScaleType和图片的ScaleType不一致时,占位图和图片就会有一个ScaleType不对,怎么解决呢,我这边是通过listener巧妙的解决了这个问题,代码如下:

    public static void display(ImageView imageView, String url) {
        Glide.with(imageView.getContext()).load(url)
                .listener(new SGlideRequestListener(imageView, ImageView.ScaleType.FIT_XY, ImageView.ScaleType.CENTER_CROP))
                .transition(new DrawableTransitionOptions().crossFade())
                .into(imageView);
    }

    static class SGlideRequestListener implements RequestListener<String, GlideDrawable> {
        private ImageView.ScaleType mPlaceScaleType;
        private ImageView.ScaleType mActualScaleType;
        private ImageView mImageView;

        SGlideRequestListener(ImageView mImageView, ImageView.ScaleType placeScaleType, ImageView.ScaleType actualScaleType){
            this.mPlaceScaleType = placeScaleType;
            this.mActualScaleType = actualScaleType;
            this.mImageView = mImageView;
            mImageView.setScaleType(placeScaleType);
        }
        @Override
        public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
            mImageView.setScaleType(mPlaceScaleType);
            return false;
        }

        @Override
        public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
            mImageView.setScaleType(mActualScaleType);
            return false;
        }
    }

当需要提前预下载好图片, 可以使用preload()方法

    public static void preloadImage(String url) {
        if (TextUtils.isEmpty(url)) {
            return;
        }
        Glide.with(SSTApplication.getContext())
                .load(url)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .preload();
    }

当需要通过url获取缓存文件对象时

    private static File getCachedFile(String url) {
        if (TextUtils.isEmpty(url)) {
            return null;
        }
        File localFile = DiskLruCacheWrapper.get(Glide.getPhotoCacheDir(SSTApplication.getContext()),
                DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE).get(new OriginalKey(url, EmptySignature.obtain()));
        Logger.d(TAG,localFile!=null?localFile.getAbsolutePath():"null");
        return localFile;
    }

    static class OriginalKey implements Key {
        private final String id;
        private final Key signature;
        private OriginalKey(String id, Key signature) {
            this.id = id;
            this.signature = signature;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            OriginalKey that = (OriginalKey) o;
            return id.equals(that.id) && signature.equals(that.signature);
        }

        @Override
        public int hashCode() {
            int result = id.hashCode();
            result = 31 * result + signature.hashCode();
            return result;
        }

        @Override
        public void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException {
            messageDigest.update(id.getBytes(STRING_CHARSET_NAME));
            signature.updateDiskCacheKey(messageDigest);
        }
    }

根据url判断图片是否下载

File localFile = DiskLruCacheWrapper.get(Glide.getPhotoCacheDir(SSTApplication.getContext()),
                DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE).get(new OriginalKey(url, EmptySignature.obtain()));
return localFile!=null;

清除当前url的缓存

File localFile = DiskLruCacheWrapper.get(Glide.getPhotoCacheDir(SSTApplication.getContext()),
                DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE).get(new OriginalKey(url, EmptySignature.obtain()));
if(file != null)
      file.delete();

通过自定义View实现Fresco的viewAspectRatio宽高比功能

public class SImageView extends AppCompatImageView {
    private float mAspectRatio = 0;
    public SImageView(Context context) {
        this(context,null);
    }

    public SImageView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public SImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    private void init(AttributeSet attrs) {
        final TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.SImageView);
        if(typedArray != null) {
            if (typedArray.hasValue(R.styleable.SImageView_viewAspectRatio)) {
                mAspectRatio = typedArray.getFloat(R.styleable.SImageView_viewAspectRatio,0);
            }
            typedArray.recycle();
        }
    }

    public void setAspectRatio(float aspectRatio){
        if(mAspectRatio != 0) {
            mAspectRatio = aspectRatio;
            requestLayout();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if(mAspectRatio != 0) {
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int height = (int) (width / mAspectRatio);
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

attrs.xml

<declare-styleable name="SImageView">
      <attr name="viewAspectRatio" format="float"/>
</declare-styleable>

布局文件中只要在SImageView设置app:viewAspectRatio属性即可,
如:

<com.soaic.widget.SImageView
                android:id="@+id/image"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:viewAspectRatio="2"  />

OK, 以上就是我在项目中遇到的一些坑及解决方法,希望对大家有所帮助!

    原文作者:肖赛Soaic
    原文地址: https://www.jianshu.com/p/deccde405e04
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞