Glide 知识梳理(1) - 基本用法

一、概述

本文的内容大部分都是参考了下面这个链接中Glide分类的文章:

https://futurestud.io/tutorials/glide-getting-started

为了区分,我们这篇只介绍一些基本用法,掌握这些基本就可以在项目中使用Glide了,而关于如何自定义Target/Glide Module等高级的用法,之后再进行讨论。

二、导入依赖包&加载网络静态图片

在使用前,首先需要在build.gradle中引入:

dependencies {
    //....
    compile 'com.github.bumptech.glide:glide:3.7.0'
    //...
}

下面是Glide加载一张网络静态图片最基本的用法:

Glide
.with(this) //传入关联的Context,如果是Activity/Fragment,那么它会根据组件当前的状态来控制请求。
.load("http://i.imgur.com/DvpvklR.png") //需要加载的图片,大多数情况下就是网络图片的链接。
.into(getImageView()); //用来展现图片的ImageView.

三、load的其它用法

在第二章的例子当中,当我们调用完.with(Context context)之后,会返回一个RequestManager对象,之前我们就是调用它的load(String string)方法,除此之外,还提供了下面的这些load方法,load方法最终会返回一个DrawableTypeRequest<xxxx>,而xxx就是我们传入的参数的类型:

  • load(byte[] model),从byte[]中读取
  • load(File file),从File中读取
  • load(Integer resourceId),从resourceId中读取
  • load(String string),从String当中读取,这个一般对应于网络图片的链接,这个图片有可能是普通的图片,也可能是一个Gif,当我们需要展示一个Gif图片时,只需要像加载普通图片一样就可以了,在加载完之后,这个Gif会被自动播放。
  • load(T model),从任意类型T的中读取,这个后面讲到自定义Model时再介绍
  • load(Uri uri),从Uri类型中读取,这个Uri必须能够被UriLoader识别。
  • loadFromMediaStore(Uri uri),从媒体设备的Uri中读取,这个方法用来展示一个本地媒体视频的缩略图,也就是视频的第一帧,需要注意,这个链接只能是本地的,网络上视频链接地址是无效的。

下面是各个方法加载的例子:

    //从byte[]中加载.
    public void loadByteArray(View view) {
        Bitmap sourceBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.book_local);
        ByteArrayOutputStream bArrayOS = new ByteArrayOutputStream();
        sourceBitmap.compress(Bitmap.CompressFormat.PNG, 100, bArrayOS);
        sourceBitmap.recycle();
        byte[] byteArray = bArrayOS.toByteArray();
        try {
            bArrayOS.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Glide.with(this)
                .load(byteArray)
                .into(mImageView);
    }
    //从File中加载.
    public void loadFile(View view) {
        String storePath = "mnt/sdcard/book_local.jpg";
        File file = new File(storePath);
        Glide.with(this)
                .load(file)
                .into(mImageView);
    }
    //从resourceId中加载.
    public void loadResourceId(View view) {
        Glide.with(this)
                .load(R.drawable.book_local)
                .into(mImageView);
    }
    //从普通url中加载.
    public void loadNormalUrl(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")
                .into(mImageView);
    }
    //从gif加载.
    public void loadGif(View view) {
        Glide.with(this)
                .load("http://s1.dwstatic.com/group1/M00/66/4D/d52ff9b0727dfd0133a52de627e39d2a.gif")
                .diskCacheStrategy(DiskCacheStrategy.SOURCE) //要加上这句,否则有可能会出现加载很慢,或者加载不出来的情况.
                .into(mImageView);
    }
    //从本地媒体视频中加载.
    public void loadMedia(View view) {
        String storePath = "mnt/sdcard/media.mp4";
        File file = new File(storePath);
        Glide.with(this)
                .load(Uri.fromFile(file))
                .into(mImageView);
    }

四、占位图片和错误图片

4.1 显示占位图片

有时候由于网络原因,导致请求耗时,此时就需要在得到图片资源之前,采用一个占位图片,这样就不会显得界面太空,placeHolder就是做这个事的,当我们调用了into方法之后,如果需要从网络上获取图片,那么它会先展示placeHolder设置的图片,placeHolder除了支持传入resourceId,还支持直接传入一个Drawable对象。

    @Override
    public DrawableRequestBuilder<ModelType> placeholder(int resourceId) {
        super.placeholder(resourceId);
        return this;
    }
    @Override
    public DrawableRequestBuilder<ModelType> placeholder(Drawable drawable) {
        super.placeholder(drawable);
        return this;
    }

使用placeHolder的例子:

    public void loadHolder(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")
                .placeholder(R.drawable.book_placeholder)
                .into(mImageView);
    }

4.2 显示错误图片

有时候,当我们请求网络图片失败时,我们希望给用户一些提示,这时候给它设置一些回调,并在回调当中进行处理。但是一般情况下,我们显示一个表示错误的本地图片就可以了,为了和前面加载时的占位图片区分,它提供了另一个error()方法,和placeHolder类似,我们可以给它传入一个resourceId或者Drawable对象。

    public void loadHolderError(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png") 
                .asGif()  //为了模拟加载失败的情况.
                .placeholder(R.drawable.book_placeholder)
                .error(R.drawable.book_error)
                .into(mImageView);
    }

上面为了模拟失败的情况,我们传入了一个png的链接,但是指定为加载asGif()资源。
我们发现它会先展示placeHolder的资源,再展示error的资源。

4.3 定义图片切换动画

无论是placeHolder还是error,都会涉及到切换ImageView的图片,这时我们可以通过设置一个动画来让这个切换的过程显得不那么突兀,默认情况下动画是开启的,crossFade有下面这三个重载方法:

  • crossFade():采用默认动画和默认时长。
  • crossFade(int duration):采用默认动画,自定义时长。
  • crossFade(int animationId, int duration):采用自定义动画,并自定义时长。
    public void loadCustomCrossFade(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")
                .placeholder(R.drawable.book_placeholder)
                .crossFade(5000) //改变的时长.
                .into(mImageView);
    }

4.4 关闭切换动画

当然我们也可以通过dontAnimate,来关闭动画,这样在切换的时候就不会出现动画。

    public void loadNoCrossFade(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")
                .placeholder(R.drawable.book_placeholder)
                .dontAnimate()
                .into(mImageView);
    }

五、获得图片资源后,进行裁剪

5.1 裁剪

Picasso相比,Glide提供了一种更加高效的处理方式,它会把内存和缓存中的图片限制到所展示的ImageView的返回内,Picasso也可以实现这一功能,但是需要调用fit()方法。在使用Glide时,如果我们不希望它自动地去匹配ImageView的宽高,那么可以调用override(width, height),这样图片资源在被展示之前就会裁剪为指定的大小。

这个方法还有另一种场景,就是当我们确切的知道需要加载多大的图片,但是此时ImageView的宽高并没有得到。

5.2 定义裁剪的方式

因为有时候采用override直接裁剪图片有可能导致只裁剪到了不必要的信息,因此Glide还提供了两个类似于ImageView中的scaleType属性:

  • centerCrop:使原始的图片的宽高按同等比例放大到override所指定的大小,并裁剪到多余的部分,这时最终的图片资源的大小为(width, height)
  • fitCenter:使得原始图片的宽高放大到小于等于override所指定的宽高,因此,我们最终得到图片的大小有可能不为(width, height),也就是说不会撑满整个ImageView
    下面是相关的代码:
    public void loadOverride(View view) {
        Glide.with(this)
                .load(R.drawable.shader_pic)
                .override(20, 20)
                .into(mImageView);
    }

    public void loadOverrideCenterCrop(View view) {
        Glide.with(this)
                .load(R.drawable.shader_pic)
                .override(20, 20)
                .centerCrop()
                .into(mImageView);
    }

    public void loadOverrideFitCenter(View view) {
        Glide.with(this)
                .load(R.drawable.shader_pic)
                .override(20, 20)
                .fitCenter()
                .into(mImageView);
    }

5.3 和ImageViewscaleType的关系

由于ImageView的展示还需要受android:scaleType的影响,这里情况有很多,所以上面裁剪出来,并不是说在ImageView里面展示就是20 * 20,具体会出现的情况很多,这个之后再专门分析。

六、Gif图片

在第二节中,我们简单的介绍了如何用Glide展示Gif图片的展示,下面我们深入地讨论一下其它两点。

5.1 asGif()

有时候,我们获取的Gif图片链接是服务器配置的,因此我们无法知道这个链接到底是不是一个Gif图片。这时我们可以配置一个asGif()选项,这样Glide就会知道我们是需要加载一个Gif图片,当这个链接不是Gif时,加载就会失败,如果我们定义了.error(xxx),就会展示这个失败的图片。
例如,下面这段代码就会失败:

    public void loadHolderError(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")  //传入的是一个静态图片的链接.
                .asGif()  //为了模拟加载失败的情况.
                .placeholder(R.drawable.book_placeholder)
                .error(R.drawable.book_error)
                .into(mImageView);
    }

5.2 asBitmap()

现在讨论另外一种情况,在列表当中,虽然我们获得的是Gif链接,但是我们希望这时候不让它播放,这时候就可以指定asBitmap(),那么就只会展示Gif图片的第一帧。

5.3 定义缓存

如果我们使用了.diskCacheStrategy(DiskCacheStrategy.SOURCE),那么Gif资源的加载将会更快。

六、缓存策略

对于任何一个网络图片加载框架来说,缓存无疑是最关键的部分,Glide使用了内存和磁盘缓存来避免不必要的网络请求,同时它也提供了一系列地接口让使用者自定义缓存策略。

6.1 内存缓存策略

默认情况下,Glide会将图片资源缓存到内存当中。而如果使用了skipMemoryCache(true)Glide不会将这张图片缓存到内存当中。
有一点需要注意:如果之前对某个指向url的图片使用了内存缓存,后面又用skipMemoryCache(true)声明想让同一个url不缓存到内存中,那么是不会生效的。

6.2 磁盘缓存策略

当某个图片变化很快时,我们有可能不需要将它缓存到磁盘当中,我们可以采用diskCacheStrategy(int mode)来定义缓存的策略,Glide默认情况下既会缓存原始的图片,也会缓存解析后的图片,举个例子,假如服务器上的图片是1000 * 1000,而ImageView的大小只有500 * 500,默认情况下Glide会缓存这两个版本的图片,我们可以设定的磁盘缓存类型有下面四种:

  • DiskCacheStrategy.NONE:不缓存
  • DiskCacheStrategy.SOURCE:只缓存原始大小的图片,也就是1000 * 1000
  • DiskCacheStrategy.RESULT:只缓存解析之后的图片,也就是上面500 * 500的图片,也就是说假如我们有两个不同大小的ImageView,用他们加载同一个url的图片,那么最终磁盘当中会有两份不同大小的图片资源。
  • DiskCacheStrategy.ALL:缓存所有版本的图片。

现在我们介绍一下采用了DiskCacheStrategy.RESULT后的缓存文件名的命名策略,具体可以参考下面这篇文章:

https://github.com/bumptech/glide/wiki/Caching-and-Cache-Invalidation

缓存文件的命名会依赖于四个部分:

  • DataFechergetId()方法的返回值,一般情况下就是Data ModeltoString方法。对于传入String类型的网络链接而言,就是url,而如果是File,那么就是Filepath
  • 目标的宽高,如果定义了override(width, height),那就是指定的数值,默认情况下是TargetgetSize()方法,也就是ImageView的宽高。
  • 用来加载和缓存图片的encodersdecoderstoString方法。
  • 在加载时的可选签名,这个方法在某些特殊的场景下很有用,例如加载的url没有变,但是服务器上这个url对应的图片资源更新了,我们就可以通过.signature(xxx)来刷新缓存。

6.3 两种策略的关系

上面我们讨论了两种缓存策略的定义,这两种策略是相互独立的,默认情况下内存的缓存为打开,而磁盘的缓存策略为DiskCacheStrategy.ALL

七、请求优先级

有时候,在同一个界面上我们会展示多个图片,而为了用户体验,那么某个图片我们希望先加载出来,这时候就可以采用.priority(int priority)来定义请求的优先级,当然,这些优先级只是给Glide作为参考,因为还涉及到图片的大小,服务器的响应事件和网络环境等因素,最后图片展示的顺序并不一定是根据优先级来的,可选的优先级包括:

  • Priority.LOW
  • Priority.NORMAL
  • Priority.HIGH
  • Priority.IMMEDIATE

八、缩略图

前面,我们介绍了placeHolder,它可以指定一个本地资源,用来在网络资源加载完成之前进行展示,而thumbnails则可以认为是一个动态的placeHolder,与placeHolder不同,我们可以给它指定一个网络图片链接。如果这个缩略图请求在load请求之前返回那么,那么会先展示这个图片,等到load请求返回之后,这个图片就会消失。假如缩略图的请求在load请求之后返回,那么请求结果会被丢弃掉。
Glide提供了两种指定缩略图的方式:

8.1 Simple Thumbnails

    public void loadScaleThumbnail(View view) {
        Glide.with(this)
                .load("http://i.imgur.com/DvpvklR.png")
                .diskCacheStrategy(DiskCacheStrategy.NONE)
                .thumbnail(0.1f)
                .into(mImageView);
    }

8.2 Complete Different Request

thumbnails还支持传入一个Glide Request作为参数,这个请求和原本的请求是相互独立的,我们可以给它指定一个完全不同的url、缓存策略、大小等等。

    public void loadRequestThumbnail(View view) {
        DrawableRequestBuilder<String> thumbnailRequest = Glide
                .with(this)
                .load("http://i.imgur.com/DvpvklR.png");
        Glide.with(this)
                .load("http://s1.dwstatic.com/group1/M00/66/4D/d52ff9b0727dfd0133a52de627e39d2a.gif")
                .diskCacheStrategy(DiskCacheStrategy.NONE)
                .thumbnail(thumbnailRequest)
                .into(mImageView);
    }

推荐阅读更多精彩内容