我要使用Glide

图片框架千千万,使用Glide最方便 (个人感觉,仅供参考)

之前使用过Picasso,一直都觉得很好用,直到有一次,在ListView中每个item都需要加载一张大图,滑动起来总有卡顿的效果,蛋痛,不知道是不是我使用的姿势没对,总感觉流畅性上面差了很多,换了Glide,内存开销小了,读取缓存更快了,页面也不卡顿了,再也不用担心这样那样的问题了。。。

送上大神对Picasso和Glide的PK博文,各有优势,自行选择

Glide不仅是Google的 “亲儿子”,更为重要的是,它支持加载GIF,这个很关键啊,,有木有

参见了郭神的Glide源码分析,在此记录下自己学习Glide的过程

使用

当前使用的是 Glide 3.7.0 稳定版 比较新的4.0 RC版应该也差不多

将Glide库引入到项目中,app->build.gradle文件中添加依赖
dependencies{ compile 'com.github.bumptech.glide:glide:3.7.0' }
或者在直接去github上下载相应的jar包导入工程libs目录下
Glide jar集中营 由衷感谢Glide开发团队的贡献
喜欢拿个挑哪个,导入后记得Add To Library

总是忘记添加权限的盆友(说的就是我自己)
<uses-permission android:name="android.permission.INTERNET" />

准备就绪,可以开始搞事情了

Glide.with(this)
      .load(url)
      .asBitmap()
      .placeholder(R.mipmap.temp)
      .error(R.mipmap.error)
      .diskCacheStrategy(DiskCacheStrategy.NONE)
      .override(100, 100)
      .into(imageView);

一句话完成了我能想得到的所有基本功能,接下来搞懂每个方法到底干了些什么事情

方法梳理

with()方法,创建并返回了一个RequestManager实例,是Glide用于管理和启动请求的核心,入参包括 Context,Activity,Fragment 。需要注意的是with()方法中传入的实例会决定Glide加载图片的生命周期,如果入参是Activity或者Fragment的实例,Glide加载图片的生命周期会跟随实例的生命周期执行、暂停或停止加载图片。如果入参是ApplicationContext,那么Glide加载图片的生命周期则跟随应用程序的生命周期,即只有当程序被杀掉的时候,图片加载才会停止。

load()方法,指定代加载的图片资源,上面传入的url其实是一个String,即网络图片的地址,但Glide是可以加载各种各样的图片资源的,包括网络图片(通常为String,图片的全路径地址),本地图片(File文件),应用资源(R.drawable.xx或者R.mipmap.xx),二进制流(byte[]),Uri对象 and so on,load()方法有很多重载,直接调用传入相应参数即可。

into()方法,指定图片显示的View,当然也不仅仅只是指定View,它还有很多高级的用法,后面再说。

以上就是Glide基本使用的三步,一句话,三个方法就可以让你起飞

完成图片加载,上面三步就足够了,Glide的强大还在于提供了很多丰富的API接口,接着学习其他扩展方法,扩展方法的使用都是串接在 load()into()方法之间

asBitmap()方法 用于指定图片格式,与之相应的还有 asGif()
asBitmap() 用于指定加载普通的静态图片,jpg、png等等
asGif() 用于指定加载gif动图
当不指定图片格式时,Glide内部会自动判断图片格式然后加载,但是指定图片格式后,加载不相应格式的图片会出现以下情况:
指定 asBitmap() 后加载动态图,只会显示静态图(动图第一帧)
指定 asGif() 后加载静态图,会加载 error() 方法指定的加载失败占位图

placeholder()方法 用于指定加载过程中的占位图,它的入参可以应用资源(mipmap和drawable),也可以是Drawable绘制的占位。Glide有很长强大的缓存机制,已加载过的图片会直接从缓存读取,加载非常快速,所以可能指定的占位图来不及现实占位图片就加载完成,如果非要看占位效果,配合 diskCacheStrategy(DiskCacheStrategy.NONE) 方法味道更好。

error()方法 指定异常占位图,因异常情况导致图片加载失败(网络不好,图片地址有误等等)时,就会加载异常占位图。

diskCacheStrategy()方法 当传入参数为 DiskCacheStrategy.NONE 时可以禁用掉Glide的缓存功能。

override()方法 指定图片大小,通常情况下,使用Glide是不需要指定图片大小的,因为Glide会自动根据加载图片View的尺寸来缓存图片,大大节省了内存的开销,牛逼吧。但是如果非得要重设图片大小,那就使用override()吧。

多说两句

基本的扩展方法就学习完毕了,大多数情况都够用了,但是我想记录的还有一个 transform() 方法,不管其他人需不需要,反正我是真的很需要#####

其实针对transform(),github上有大神已经搞出来了基于Glide图片裁剪相关的库,附上传送门 glide-transformations ,但还是想自己多学习和了解一下相关的内容

针对项目中各式各样的需求,基本的原图加载很多时候不能满足我们的需求,很多时候都需要对待加载的图片做各式各样的处理,如:现在大部分app中的用户头像都需要呈圆形展示,有些地方的图片列表需要带圆角展示,又或者有些图片需要高斯模糊等等。。。当然你可以直接使用自定义的圆形ImageView、圆角ImageView,但Glide中是支持自定义图形裁剪的,直接使用就好了。

Glide自带有两个裁剪方法

centerCrop() 方法 缩放图像让它填充到ImageView界限内并裁剪额外的部分(ImageView会被完全填充,但图像可能不会完整展示)

fitCenter() 方法 缩放图像让图像测量出的大小等于或小于ImageView的边界范围(图像会完全展示,但可能不会充满整个ImageView)

直接使用就可以了
Glide.with(this) .load(url) .asBitmap() .centerCrop() //.fitCenter() .placeholder(R.mipmap.temp) .error(R.mipmap.error) .diskCacheStrategy(DiskCacheStrategy.NONE) .override(100, 100) .into(imageView);

关于ImageView的scaleType属性和Glide的裁剪属性的关系可以参照这篇博文
Glide裁剪和ImageView的scaleType的关系

前面已经说了,可能在实际应用中还需要各种其他形状或者效果的裁剪,只需要自定义一个继承自BitmapTransform的类,然后根据自己的需要重写 transform() 方法,下面给出圆角和圆形参见的实例

圆形裁剪

public class CirCleTransform extends BitmapTransformation {

    public CirCleTransform(Context context) {
        super(context);
    }

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

    private Bitmap circleCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

        int size = Math.min(source.getWidth(), source.getHeight());
        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;

        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);

        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        float r = size / 2f;
        canvas.drawCircle(r, r, r, paint);
        return result;
    }

    @Override
    public String getId() {
        return getClass().getName();
    }
}

圆角裁剪

public class RoundTransform extends BitmapTransformation {

    public enum CornerType {
        ALL,
        TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,
        TOP, BOTTOM, LEFT, RIGHT,
        OTHER_TOP_LEFT, OTHER_TOP_RIGHT, OTHER_BOTTOM_LEFT, OTHER_BOTTOM_RIGHT,
        DIAGONAL_FROM_TOP_LEFT, DIAGONAL_FROM_TOP_RIGHT
    }

    private int mRadius;
    private int mDiameter;
    private int mMargin;
    private CornerType mCornerType;

    /**
     * 构造函数 默认圆角半径4dp, 默认间距为0dp, 默认为全角模式
     *
     * @param context Context
     */
    public RoundTransform(Context context) {
        this(context, 5, 0, CornerType.ALL);
    }

    /**
     * 构造函数
     *
     * @param context Context
     * @param radius  圆角半径
     * @param margin  边距
     */
    public RoundTransform(Context context, int radius, int margin) {
        this(context, radius, margin, CornerType.ALL);
    }

    public RoundTransform(Context context, int radius, int margin, CornerType cornerType) {
        super(context);
        this.mRadius = (int) Resources.getSystem().getDisplayMetrics().density * radius;
        this.mMargin = margin;
        this.mDiameter = mRadius * 2;
        this.mCornerType = cornerType;
    }

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

    private 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);
        drawRoundRect(canvas, paint, source.getWidth(), source.getHeight());
        return result;
    }

    private void drawRoundRect(Canvas canvas, Paint paint, int width, int height) {
        float right = width - mMargin;
        float bottom = height - mMargin;
        switch (mCornerType) {
            case ALL:
                canvas.drawRoundRect(new RectF(mMargin, mMargin, right, bottom), mRadius, mRadius, paint);
                break;
            case TOP_LEFT:
                drawTopLeftRoundRect(canvas, paint, right, bottom);
                break;
            case TOP_RIGHT:
                drawTopRightRoundRect(canvas, paint, right, bottom);
                break;
            case BOTTOM_LEFT:
                drawBottomLeftRoundRect(canvas, paint, right, bottom);
                break;
            case BOTTOM_RIGHT:
                drawBottomRightRoundRect(canvas, paint, right, bottom);
                break;
            case TOP:
                drawTopRoundRect(canvas, paint, right, bottom);
                break;
            case BOTTOM:
                drawBottomRoundRect(canvas, paint, right, bottom);
                break;
            case LEFT:
                drawLeftRoundRect(canvas, paint, right, bottom);
                break;
            case RIGHT:
                drawRightRoundRect(canvas, paint, right, bottom);
                break;
            case OTHER_TOP_LEFT:
                drawOtherTopLeftRoundRect(canvas, paint, right, bottom);
                break;
            case OTHER_TOP_RIGHT:
                drawOtherTopRightRoundRect(canvas, paint, right, bottom);
                break;
            case OTHER_BOTTOM_LEFT:
                drawOtherBottomLeftRoundRect(canvas, paint, right, bottom);
                break;
            case OTHER_BOTTOM_RIGHT:
                drawOtherBottomRightRoundRect(canvas, paint, right, bottom);
                break;
            case DIAGONAL_FROM_TOP_LEFT:
                drawDiagonalFromTopLeftRoundRect(canvas, paint, right, bottom);
                break;
            case DIAGONAL_FROM_TOP_RIGHT:
                drawDiagonalFromTopRightRoundRect(canvas, paint, right, bottom);
                break;
            default:
                canvas.drawRoundRect(new RectF(mMargin, mMargin, right, bottom), mRadius, mRadius, paint);
                break;
        }
    }

    @Override
    public String getId() {
        return "RoundedTransformation(radius=" + mRadius + ", margin=" + mMargin + ", diameter="
                + mDiameter + ", cornerType=" + mCornerType.name() + ")";
    }

    private void drawTopLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, mMargin + mDiameter),
                mRadius, mRadius, paint);
        canvas.drawRect(new RectF(mMargin, mMargin + mRadius, mMargin + mRadius, bottom), paint);
        canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);
    }

    private void drawTopRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, mMargin + mDiameter), mRadius,
                mRadius, paint);
        canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);
        canvas.drawRect(new RectF(right - mRadius, mMargin + mRadius, right, bottom), paint);
    }

    private void drawBottomLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, mMargin + mDiameter, bottom),
                mRadius, mRadius, paint);
        canvas.drawRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom - mRadius), paint);
        canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);
    }

    private void drawBottomRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(right - mDiameter, bottom - mDiameter, right, bottom), mRadius,
                mRadius, paint);
        canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);
        canvas.drawRect(new RectF(right - mRadius, mMargin, right, bottom - mRadius), paint);
    }

    private void drawTopRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,
                paint);
        canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right, bottom), paint);
    }

    private void drawBottomRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,
                paint);
        canvas.drawRect(new RectF(mMargin, mMargin, right, bottom - mRadius), paint);
    }

    private void drawLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,
                paint);
        canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom), paint);
    }

    private void drawRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,
                paint);
        canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom), paint);
    }

    private void drawOtherTopLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,
                paint);
        canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,
                paint);
        canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom - mRadius), paint);
    }

    private void drawOtherTopRightRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,
                paint);
        canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, right, bottom), mRadius, mRadius,
                paint);
        canvas.drawRect(new RectF(mMargin + mRadius, mMargin, right, bottom - mRadius), paint);
    }

    private void drawOtherBottomLeftRoundRect(Canvas canvas, Paint paint, float right, float bottom) {
        canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,
                paint);
        canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, bottom), mRadius, mRadius,
                paint);
        canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right - mRadius, bottom), paint);
    }

    private void drawOtherBottomRightRoundRect(Canvas canvas, Paint paint, float right,
                                               float bottom) {
        canvas.drawRoundRect(new RectF(mMargin, mMargin, right, mMargin + mDiameter), mRadius, mRadius,
                paint);
        canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, bottom), mRadius, mRadius,
                paint);
        canvas.drawRect(new RectF(mMargin + mRadius, mMargin + mRadius, right, bottom), paint);
    }

    private void drawDiagonalFromTopLeftRoundRect(Canvas canvas, Paint paint, float right,
                                                  float bottom) {
        canvas.drawRoundRect(new RectF(mMargin, mMargin, mMargin + mDiameter, mMargin + mDiameter),
                mRadius, mRadius, paint);
        canvas.drawRoundRect(new RectF(right - mDiameter, bottom - mDiameter, right, bottom), mRadius,
                mRadius, paint);
        canvas.drawRect(new RectF(mMargin, mMargin + mRadius, right - mDiameter, bottom), paint);
        canvas.drawRect(new RectF(mMargin + mDiameter, mMargin, right, bottom - mRadius), paint);
    }

    private void drawDiagonalFromTopRightRoundRect(Canvas canvas, Paint paint, float right,
                                                   float bottom) {
        canvas.drawRoundRect(new RectF(right - mDiameter, mMargin, right, mMargin + mDiameter), mRadius,
                mRadius, paint);
        canvas.drawRoundRect(new RectF(mMargin, bottom - mDiameter, mMargin + mDiameter, bottom),
                mRadius, mRadius, paint);
        canvas.drawRect(new RectF(mMargin, mMargin, right - mRadius, bottom - mRadius), paint);
        canvas.drawRect(new RectF(mMargin + mRadius, mMargin + mRadius, right, bottom), paint);
    }
}

圆角裁剪也是参照了 glide-transformations 库搞出来的,支持指定圆角的裁剪,只需传入相应的 CornerType 即可

问题小记 之前在使用自定义裁剪的时候出了一个这样的问题:
Glide.with(mContext).load(url).transform(new CircleTransform()).into(imageView); 这样加载圆形图片没有问题

Glide.with(mContext).load(url).transform(new RoundTransform(mContext)).into(imageView); 这样加载圆角图片就不起作用了
什么鬼?没搞懂啊,没有使用 centerCrop() 或者 fitCenter() 方法啊,闹哪样啊,研究了好久,发现这样使用 Glide.with(mContext).load(url).transform(new CenterCrop(), new RoundTransform(mContext)).into(imageView); 就起作用了,也没有搞懂为什么,先记录下来,后面弄懂了再来解释。

嫌麻烦可以直接使用 glide-transformations 库,里面提供了基本上我能想到的所有裁剪效果

至于Glide原理的话,相信郭神的那四篇文章已经足够啃好久好久了,附上传送门
Android图片加载框架最全解析(一),Glide的基本用法
Android图片加载框架全面解析(二),从源码角度理解Glide的执行流程
Android图片加载框架最全解析(三),深入探究Glide的缓存机制
Android图片加载框架最全解析(四),玩转Glide的回调与监听




----------普通人看到了希望才坚持,疯子坚持了才看到希望----------
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容