Glide详解(基于3.X版本)

一.简介

Glide,一个被google所推荐的图片加载库,作者是bumptech。这个库被广泛运用在google的开源项目中,包括2014年的google I/O大会上发布的官方app。Glide 对于 Android SDK 的最低要求是 API level 10。Glide滑行的意思,可以看出这个库的主旨就在于让图片加载变的流畅。现在被广泛使用。Glide内部HTTP通讯组件的底层实现是基于HttpUrlConnection来进行定制的。

 

图解

 

特点

1.图片缓存和媒体缓存。Glide 不仅是一个图片缓存,它支持 Gif、WebP、缩略图。甚至是 Video。

2.支持优先级处理。

3.与Activity/Fragment 生命周期一致,支持 trimMemory。Glide 对每个 context 都保持一个RequestManager,通过 FragmentTransaction 保持与 Activity/Fragment 生命周期一致,并且有对应的trimMemory 接口实现可供调用。

4.支持 okhttp、Volley。Glide 默认通过 UrlConnection 获取数据,可以配合 okhttp 或是 Volley 使用。实际 ImageLoader、Picasso 也都支持 okhttp、Volley。

5.内存友好

(1) Glide 的内存缓存有个 active 的设计。从内存缓存中取数据时,不像一般的实现用 get,而是用 remove,再将这个缓存数据放到一个 value 为软引用的 activeResources map 中,并计数引用数,在图片加载完成后进行判断,如果引用计数为空则回收掉。

(2) 内存缓存更小图片。Glide 以 url、view_width、view_height、屏幕的分辨率等做为联合 key,将处理后的图片缓存在内存缓存中,而不是原始图片以节省大小。

(3) 与 Activity/Fragment 生命周期一致,支持 trimMemory。

(4) 图片默认使用默认 RGB_565 而不是 ARGB_888。虽然清晰度差些,但图片更小,也可配置到ARGB_888。

6.其他:Glide 可以通过 signature 或不使用本地缓存支持 url 过期。

 

 

 

 

 

 

二.代码说明

1.Gradle配置

implementation 'com.github.bumptech.glide:glide:3.7.0'

jar链接:https://github.com/bumptech/glide/releases

 

 

 

2.最基本的用法

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
     .load(url)
     .into(imageview);

<1> .with(Context context):上下文,这里还可以使用 Activity/FragmentActivity对象。将 Activity/Fragment 对象作为参数的好处是,图片的加载会和 Activity/Fragment 的生命周期保持一致,例如:onPaused 时暂停加载,onResume 时又会自动重新加载。所以在传参的时候建议使用 Activity/Fragment 对象,而不是 Context。

<2> .load(url):加载url对应的图片。

<3> .into(ImageView imageView):要显示图片的目标ImageView。

 

Glide可以加载几种不同路径下的图片

<1> 加载本地图片 比如sd卡中的图片

ImageView imageview=findViewById(R.id.activity_listview_imageview);
File file = new File(Environment.getExternalStorageDirectory() + "/icon.png");
Glide.with(this)
     .load(file)
     .into(imageview);

 

<2> 加载应用资源 比如mipmap下的图片

ImageView imageview=findViewById(R.id.activity_listview_imageview);	  
int resource = R.mipmap.za;
Glide.with(this)
     .load(resource)
     .into(imageview);

 

<3> 加载应用资源 比如asset下的图片

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String prefixurl="file:///android_asset/";
Glide.with(this)
     .load(prefixurl+"tab_my_pressed.png")
     .into(imageview);

 

<4> 加载二进制流 比如从服务器获取的图片流

ImageView imageview=findViewById(R.id.activity_listview_imageview);
byte[] image =XXX;
Glide.with(this)
     .load(image)
     .into(imageview);

 

<5> 加载Uri对象 比如获取的相机相册图片

ImageView imageview=findViewById(R.id.activity_listview_imageview);	  
Uri imageUri =XXX;
Glide.with(this)
     .load(imageUri)
     .into(imageview);

 

load重载方法

 

 

 

 

3.添加占位符

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
     .load(url)
     .placeholder(R.mipmap.za)//图片加载成功前显示的图片
     .error(R.mipmap.a1u)//图片加载失败后显示的图片
     .into(imageview);

<1> .placeholder(R.mipmap.za)//图片加载成功前显示的图片。

<2> .error(R.mipmap.a1u)//图片加载失败后显示的图片。

注意:placeholder() 和 error() 的参数都是只支持 int 和 Drawable 类型的参数,这种设计应该是考虑到使用本地图片比网络图片更加合适做占位图。

 

 

 

 

4.缩略图

Glide的缩略图和占位图略有不同,占位图必须使用资源文件才行,而缩略图是动态的占位图可以从网络中加载。缩略图会在世纪请求加载完成或者处理完之后才显示。在原始图片到达之后,缩略图不会取代原始图片,只会被抹除。

Glide 为缩略图提供了2种不同的加载方式,比较简单的方式是调用 thumbnail() 方法,参数是 float 类型,作为其倍数大小。例如,你传入 0.5f 作为参数,Glide 将会显示原始图片的50%的大小,如果原图是 1000x1000 的尺寸,那么缩略图将会是 500x500 的尺寸。因为缩略图可能明显比原图小得多,所以我们需要确保 ImageView 的 ScaleType 设置的正确。

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
     .load(url)
     .thumbnail(0.5f)//缩放原图50%
     .into(imageview);

使用 thumbnail() 方法来设置是简单粗暴的,但是如果缩略图需要通过网络加载相同的全尺寸图片,就不会很快的显示了。所以 Glide 提供了另一种防止去加载缩略图。

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
DrawableRequestBuilder<String> thumbnailRequest = Glide.with(GlideActivity.this).load(url);
Glide.with(GlideActivity.this)
     .load(url)
     .thumbnail(thumbnailRequest)
     .into(imageview);

与第一种方式不同的是,这里的第一个缩略图请求是完全独立于第二个原始请求的。该缩略图可以是不同的资源图片,同时也可以对缩略图做不同的转换

 

 

 

 

5.开启动画

动画效果可以让图片加载变得更加的平滑,crossFade() 方法强制开启 Glide 默认的图片淡出淡入动画,当前版本3.7.0是默认开启的。crossFade() 还有一个重载方法 crossFade(int duration)。可以控制动画的持续时间,单位ms。动画默认的持续时间是300ms。既然可以添加动画,那肯定就可以设置没有任何淡出淡入效果,调用 dontAnimate()

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
     .load(url)
     .crossFade(2000)
     .crossFade()
     .dontAnimate()
     .into(imageview);

<1> .crossFade():开启动画。

<2> .crossFade(int duration):开启动画可确定持续时间。

<3> .dontAnimate():关闭动画。

<4> 自定义动画

方式1:xml文件

anim文件

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true">

    <scale
        android:duration="@android:integer/config_longAnimTime"
        android:fromXScale="0.2"
        android:fromYScale="0.2"
        android:pivotX="30%"
        android:pivotY="30%"
        android:toXScale="1"
        android:toYScale="1"/>
</set>

java代码

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
     .load(url)
     .animate(R.anim.glidescale)
     .into(imageview);

 

方式2:Animator类

ViewPropertyAnimation自定义实现类

ViewPropertyAnimation.Animator animator = new ViewPropertyAnimation.Animator() {
   @Override
   public void animate(View view) {
       view.setAlpha(0f);
       ObjectAnimator fadeAnim = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
       fadeAnim.setDuration(3000);
       fadeAnim.start();
   }
};

java代码

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
     .load(url)
     .animate(animator)
     .into(imageview);

 

 

 

6.图片大小与裁剪

在项目开发过程中,指定图片显示大小经常用到,因为从服务器获取的图片不一定都是符合设计图的标准的。我们在这里就可以使用 override(width,height) 方法,在图片显示到 ImageView 之前,重新改变图片大小。

 ImageView imageview=findViewById(R.id.activity_listview_imageview);
 String url = "XXX";
 Glide.with(GlideActivity.this)
      .load(url)
      .override(50,50)//单位px 像素
      .into(imageview);

<1> .override(int width,int height):剪切图片。width/height单位均为px像素

在设置图片到 ImageView 的时候,为了避免图片被挤压失真,ImageView 本身提供了 ScaleType 属性,这个属性可以控制图片显示时的方式。Glide 也提供了两个类似的方法 CenterCrop() 和 FitCenter()和ImageView本身ScaleType意义相近

详情:Android Bitmap ScaleType属性以及Config详解

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
     .load(url)
     .override(50,50)//单位px 像素
     .centerCrop()
     .fitCenter()
     .into(imageview);

 

 

 

7.图片的缓存

为了更快的加载图片,我们肯定希望可以直接拿到图片,而不是进行网络请求,所以我们需要缓存。Glide 通过使用默认的内存和磁盘缓存来避免不必要的网络请求。

Glide的缓存设计可以说是非常先进的,考虑的场景也很周全。在缓存这一功能上,Glide又将它分成了两个模块,一个是内存缓存,一个是硬盘缓存。

这两个缓存模块的作用各不相同,内存缓存的主要作用是防止应用重复将图片数据读取到内存当中,而硬盘缓存的主要作用是防止应用重复从网络或其他地方重复下载和读取数据。内存缓存和硬盘缓存的相互结合才构成了Glide极佳的图片缓存效果,那么接下来我们就来分别学习一下这两种缓存的使用方法。

 

<1> 内存缓存

你要知道,默认情况下,Glide自动就是开启内存缓存的。也就是说,当我们使用Glide加载了一张图片之后,这张图片就会被缓存到内存当中,只要在它还没从内存中被清除之前,下次使用Glide再加载这张图片都会直接从内存当中读取,而不用重新从网络或硬盘上读取了,这样无疑就可以大幅度提升图片的加载效率。比方说你在一个RecyclerView当中反复上下滑动,RecyclerView中只要是Glide加载过的图片都可以直接从内存当中迅速读取并展示出来,从而大大提升了用户体验。

而Glide最为人性化的是,你甚至不需要编写任何额外的代码就能自动享受到这个极为便利的内存缓存功能,因为Glide默认就已经将它开启了。内存缓存是 Glide 默认帮我们做了的,除非你不需要,可以调用 skipMemoryCache(true) 告诉 Glide 跳过内存缓存。这样 Glide 就不会把这张图片放到内存缓存中,该方法只影响内存缓存。
 

 

<2> 磁盘缓存

磁盘缓存也是默认开启的,当然也是可以关闭的,不过关闭的方式略微有点不一样。

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
     .load(url)
     .skipMemoryCache(true)
     .diskCacheStrategy(DiskCacheStrategy.NONE)
     .into(imageview);

(1) .skipMemoryCache(true):关闭内存缓存,不设置即默认开启。

(2) .diskCacheStrategy(DiskCacheStrategy.NONE):关闭磁盘缓存,不设置即默认开启。

附 DiskCacheStrategy 的枚举意义:

DiskCacheStrategy.NONE 什么都不缓存。

DiskCacheStrategy.SOURCE 只缓存全尺寸图。

DiskCacheStrategy.RESULT 只缓存最终的加载图。

DiskCacheStrategy.ALL 缓存所有版本图(默认行为)。

 

 

 

8.图片请求的优先级

同一时间加载多个图片,App 将难以避免这种情况。如果这个时候我们希望用户的体验更好,往往会选择先加载对于用户更加重要的图片。Glide 可以调用 .priority() 方法配合 Priority 枚举来设置图片加载的优先级。

ImageView imageview1=findViewById(R.id.activity_listview_imageview1);
String url1 = "XXX";
Glide.with(GlideActivity.this)
     .load(url1)
     .priority(Priority.HIGH)
     .into(imageview1);

ImageView imageview2=findViewById(R.id.activity_listview_imageview2);
String url2 = "XXX";
Glide.with(GlideActivity.this)
      .load(url2)
      .priority(Priority.LOW)
      .into(imageview2);

priority可取值:

Priority.LOW

Priority.NORMAL

Priority.HIGH

Priority.IMMEDIAT

这里有一点需要注意,优先级并不是完全严格遵守的。Glide 将会用他们作为一个准则,尽可能的处理这些请求,但是不能保证所有的图片都会按照所有要求的顺序加载。

 

 

 

9.显示Gif和Video

显示GIf对于Glide 来说一个比较特别的功能。而且使用起来非常简单。

显示GIF方式1:asGif()方法

 ImageView imageview=findViewById(R.id.activity_listview_imageview);
 String url = "XXX";
 Glide.with(GlideActivity.this)
      .load(url)
      .asGif()
      .error(R.mipmap.za)
      .into(imageview);

用asGif()方法,如果url对应的图片不是gif类型,则直接显示.error(R.mipmap.za)设置的图片。如果是gif类型的图片则直接显示。

 

显示GIF方式2:asBitmap()方法

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
     .load(url)
     .asBitmap()
     .error(R.mipmap.za)
     .into(imageview);

用asBitmap()方法,如果url对应的图片不是gif类型,直接显示图片。如果是gif类型的图片,则显示Gif的第一帧图片。

 

所以因为图片的格式可能不确定(有时是动图,有时是静图)所以最好两个都不加,Glide框架会自行判断

Glide.with(this)
     .load("XXX")
     .error(R.mipmap.za)
     .placeholder(R.mipmap.patient_ava)
     .into(imageview);

设置 加载中 和 加载失败 要显示的图片 即可。

 

显示Video(目前只支持本地)

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = Environment.getExternalStorageDirectory()+"/123.mp4";
Glide.with(GlideActivity.this)
     .load(Uri.fromFile(new File(url)))
     .into(imageview);

显示本地视频的封面。

 

 

 

 

10.各种Target

其实通过上面的分析,我们已经知道了,into()方法还有一个接收Target参数的重载(上图)。即使我们传入的参数是ImageView,Glide也会在内部自动构建一个Target对象。而如果我们能够掌握自定义Target技术的话,就可以更加随心所欲地控制Glide的回调了。

 

Glide的所有Target

 

举例说明

1.SimpleTarget

泛型为GlideDrawable时 代码如下:(一般情况)

<1> 此时必须删除.asBitmap()方法。

<2> 在onResourceReady回调方法中获取的是GlideDrawable 所以 imageview.setImageDrawable(resource);

private void initData() {
    imageview=findViewById(R.id.activity_listview_imageview);
    loadImageSimpleTarget();
}


private void loadImageSimpleTarget() {
    String url = "XXX";
    Glide.with(GlideActivity.this)
            .load(url)
            .into(mSimpleTarget);
}

    
private SimpleTarget<GlideDrawable> mSimpleTarget = new SimpleTarget<GlideDrawable>() {
    @Override
    public void onResourceReady(GlideDrawable  resource, GlideAnimation glideAnimation) {
        imageview.setImageDrawable(resource);
    }
};

 

泛型为Bitmap时 代码如下:(确定你正在加载的是一张静态图而不是GIF图)

<1> 此时必须使用.asBitmap()方法。

<2> 在onResourceReady回调方法中获取的是Bitmap 所以 imageview.setImageBitmap(resource);

private void initData() {
   imageview=findViewById(R.id.activity_listview_imageview);
   loadImageSimpleTarget();
}

private void loadImageSimpleTarget() {
    String url = "XXX";
    Glide.with(GlideActivity.this)
          .load(url)
          .asBitmap()
          .into( mSimpleTarget );
}

private SimpleTarget<Bitmap> mSimpleTarget = new SimpleTarget<Bitmap>() {
   @Override
   public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> animation) {
       imageview.setImageBitmap(resource);
   }
};

 

利用SimpleTarget类改变图片大小 替换上面实现类

private SimpleTarget<Bitmap> mSimpleTarget = new SimpleTarget<Bitmap>(800,800) {
   @Override
   public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> animation) {
        imageview.setImageBitmap(resource);
   }
};

即显示的时候只需要是 800x800 的尺寸来节省时间和内存,你可以在 SimpleTarget 的回调声明中指定图片的大小。

从代码中可以看到 SimpleTarget 的对象的声明没有使用匿名对象,而是单独的声明了一个变量,这里是故意这么做的,如果使用匿名内部类的方式创建 SimpleTarget 的对象,这样会增大该对象在 Glide 完成图片请求之前就被回收的可能性。

上面Glide的with() 方法传入 Activity 或者 Fragment 时 Glide 的图片加载会与他们的生命周期关联起来,但是如果我们使用 Target 的话,这个 Target 就有可能独立于他们的生命周期以外,这时候我们就需要使用 context.getApplicationContext() 的上下文了,这样只有在应用完全停止时 Glide 才会杀死这个图片请求。

 

 

2.ViewTarget

ViewTarget的功能更加广泛,它可以作用在任意的View上。

自定义View

public class MyLayout extends RelativeLayout{

    private ViewTarget<MyLayout, GlideDrawable> viewTarget;

    public MyLayout(Context context) {
        super(context);
        initviewTarget();
    }

    public MyLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initviewTarget();
    }

    public void initviewTarget(){
        viewTarget = new ViewTarget<MyLayout, GlideDrawable>(this) {
            @Override
            public void onResourceReady(GlideDrawable resource, GlideAnimation glideAnimation) {
                MyLayout myLayout = getView();
                myLayout.setBackground(resource);
            }
        };
    }

    /**
     * 外界使用提供获取ViewTarget对象的方法
     * */

    public ViewTarget<MyLayout, GlideDrawable> getTarget() {
        return viewTarget;
    }

}

 

布局

<com.wjn.fragmentviewpager.view.MyLayout
  android:id="@+id/activity_glide_fatherlayout"
  android:layout_width="match_parent"
  android:layout_height="match_parent">


  ...

</com.wjn.fragmentviewpager.view.MyLayout> 

 

调用

private void initData() {
    MyLayout fatherlayout=findViewById(R.id.activity_glide_fatherlayout);
    loadLayoutViewTarget();
}

private void loadLayoutViewTarget() {
    String url = "XXX";
    Glide.with(GlideActivity.this)
          .load(url)
          .into(fatherlayout.getTarget());
}

 

关于Target的小结

<1> 一般我们都是在ImageView上显示图片,所以大部分情况下使用第一种SimpleTarget即可满足条件。

<2> 如果要在其他View上显示图片,比如RelativeLayout LinearLayout等等,此时可以使用ViewTarget。

<3> SimpleTarget的泛型一般为GlideDrawable或Bitmap。ViewTarget的第二个参数也是如此。

 

 

 

11.加载圆形图片

BitmapTransformation实现类

public class GlideCircleTransform extends BitmapTransformation {
    public GlideCircleTransform(Context context) {
        super(context);
    }

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

    private static 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;

        // TODO this could be acquired from the pool too
        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();
    }
}

 

使用

 ImageView imageview=findViewById(R.id.activity_listview_imageview);
 String url = "XXX";
 Glide.with(GlideActivity.this)
      .load(url)
      .transform(new GlideCircleTransform(GlideActivity.this))
      .into(imageview);

 

 

 

12.加载圆角图片

BitmapTransformation实现类

public class GlideRoundTransform extends BitmapTransformation {

    private float radius;

    public GlideRoundTransform(Context context, int dp) {
        super(context);
        this.radius = Resources.getSystem().getDisplayMetrics().density * dp;
    }

    @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);
        RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
        canvas.drawRoundRect(rectF, radius, radius, paint);
        return result;
    }

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

 

使用

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
     .load(url)
     .transform(new GlideRoundTransform(GlideActivity.this,20))
     .into(imageview);

 

注意 上述 加载圆形图片和加载圆角图片 都实现了BitmapTransformation类。且使用是都是使用.transform()方法。

 

 

 

 

13.使用GItHub上一个很火的自定义ImageView

GitHub链接

https://github.com/hdodenhof/CircleImageView

 

AndroidStudio配置

implementation 'de.hdodenhof:circleimageview:2.2.0'

 

布局使用

<de.hdodenhof.circleimageview.CircleImageView
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/activity_listview_circleimageview"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"
        android:layout_below="@+id/activity_listview_imageview"
        android:layout_marginTop="20dp"
        app:civ_border_width="2dp"
        app:civ_border_color="#FF0000"/>

 

调用使用(SimpleTarget的实现类,在其onResourceReady方法中给自定义的ImageView赋值)

private void loadImageSimpleTarget() {
  String url = "XXX";
  Glide.with(GlideActivity.this)
       .load(url)
       .asBitmap()
       .into( mSimpleTarget );
}

private SimpleTarget<Bitmap> mSimpleTarget = new SimpleTarget<Bitmap>() {
  @Override
  public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> animation) {
       circleImageView.setImageBitmap(resource);
  }
};

 

调用使用(直接使用Glide的into方法加载自定义的ImageView)

private void loadImageSimpleTarget() {
 String url = "XXX";
 Glide.with(GlideActivity.this)
      .load(url)
      .asBitmap()
      .into( circleImageView );
}

 

 

 

 

14.更改Glide配置项

<1> setMemoryCache() 

用于配置Glide的内存缓存策略,默认配置是LruResourceCache。

 

<2> setBitmapPool() 

用于配置Glide的Bitmap缓存池,默认配置是LruBitmapPool。

 

<3> setDiskCache() 

用于配置Glide的硬盘缓存策略,默认配置是InternalCacheDiskCacheFactory。

 

<4> setDiskCacheService() 

用于配置Glide读取缓存中图片的异步执行器,默认配置是FifoPriorityThreadPoolExecutor,也就是先入先出原则。

 

<5> setResizeService() 

用于配置Glide读取非缓存中图片的异步执行器,默认配置也是FifoPriorityThreadPoolExecutor。

 

<6> setDecodeFormat() 

用于配置Glide加载图片的解码模式,默认配置是RGB_565。

 

 

 

 

15.修改Glide的图片质量

在 Android 中有两个主要的方法对图片进行解码:ARGB_8888RGB_565 。前者为每个像素使用4个字节,后者每个像素仅使用2个字节。ARGB_8888 的有时就是图像质量更高以及能储存一个 alpha 通道。 Picasso 使用的就是 ARGB_8888 , Glide 默认使用低质量的 RGB_565 ,但是现在你就可以使用 Glide module 来改变图片解码规则。

 

自定义GlideModule实现类

public class QualityModule implements GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
        // nothing to do here
    }
}

 

清单文件中配置

 

代码使用(和普通的没有什么区别)

ImageView imageview=findViewById(R.id.activity_listview_imageview);
String url = "XXX";
Glide.with(GlideActivity.this)
      .load(url)
      .into(imageview);

 

 

 

16.修改Glide磁盘缓存(默认)

GlideModule实现类

public class MyGlideModule implements GlideModule {
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
       
    }
}

ExternalCacheDiskCacheFactory的默认硬盘缓存大小都是250M。也就是说,如果你的应用缓存的图片总大小超出了250M,那么Glide就会按照DiskLruCache算法的原则来清理缓存的图片。

当然,我们是可以对这个默认的缓存大小进行修改的。

代码

public class MyGlideModule implements GlideModule {

    public static final int DISK_CACHE_SIZE = 500 * 1024 * 1024;

    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, DISK_CACHE_SIZE));
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
        
    }
}

ExternalCacheDiskCacheFactory的默认缓存路径是在sdcard/Android/包名/cache/image_manager_disk_cache目录。

清单文件中配置如上。

 

 

 

17.自定义磁盘缓存和内存缓存

GlideModule实现类

public class MyGlideModule implements GlideModule {

    private static final int DISK_CACHE_SIZE = 100 * 1024 * 1024;
    public static final int MAX_MEMORY_CACHE_SIZE = 10 * 1024 * 1024;

    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        //设置磁盘缓存的路径 path
        final File cacheDir = new File("");
        builder.setDiskCache(new DiskCache.Factory() {
            @Override
            public DiskCache build() {
                return DiskLruCacheWrapper.get(cacheDir, DISK_CACHE_SIZE);
            }
        });
        //设置内存缓存大小,一般默认使用glide内部的默认值
        builder.setMemoryCache(new LruResourceCache(MAX_MEMORY_CACHE_SIZE));

    }

    @Override
    public void registerComponents(Context context, Glide glide) {
       
    }
}

清单文件中配置如上。

 

 

 

18.预加载

Glide加载图片虽说非常智能,它会自动判断该图片是否已经有缓存了,如果有的话就直接从缓存中读取,没有的话再从网络去下载。但是如果希望提前对图片进行一个预加载,等真正需要加载图片的时候就直接从缓存中读取,不想再等待慢长的网络加载时间了。Glide专门给我们提供了预加载的接口,也就是preload()方法,我们只需要直接使用就可以了。preload()方法有两个方法重载,一个不带参数,表示将会加载图片的原始尺寸,另一个可以通过参数指定加载图片的宽和高。 

ImageView imageview=findViewById(R.id.activity_listview_imageview);
Glide.with(this)
     .load("XXX")
     .error(R.mipmap.za)
     .placeholder(R.mipmap.patient_ava)
     .diskCacheStrategy(DiskCacheStrategy.SOURCE)
     .preload();

需要注意的是,我们如果使用了preload()方法,最好要将diskCacheStrategy的缓存策略指定成DiskCacheStrategy.SOURCE。因为preload()方法默认是预加载的原始图片大小,而into()方法则默认会根据ImageView控件的大小来动态决定加载图片的大小。因此,如果不将diskCacheStrategy的缓存策略指定成DiskCacheStrategy.SOURCE的话,很容易会造成我们在预加载完成之后再使用into()方法加载图片,却仍然还是要从网络上去请求图片这种现象。

调用了预加载之后,我们以后想再去加载这张图片就会非常快了,因为Glide会直接从缓存当中去读取图片并显示出来。

ImageView imageview=findViewById(R.id.activity_listview_imageview);
Glide.with(this)
     .load("XXX")
     .error(R.mipmap.za)
     .placeholder(R.mipmap.patient_ava)
     .diskCacheStrategy(DiskCacheStrategy.SOURCE)
     .into(imageview);

注意,这里我们仍然需要使用diskCacheStrategy()方法将硬盘缓存策略指定成DiskCacheStrategy.SOURCE,以保证Glide一定会去读取刚才预加载的图片缓存。

 

 

 

 

19.下载图片

使用Glide都是为了将图片显示到界面上。虽然我们知道Glide会在图片的加载过程中对图片进行缓存,但是缓存文件到底是存在哪里的,以及如何去直接访问这些缓存文件?我们都还不知道。

其实Glide将图片加载接口设计成这样也是希望我们使用起来更加的方便,不用过多去考虑底层的实现细节。但如果想要去访问图片的缓存文件该时就需要用到downloadOnly()方法了。

和preload()方法类似,downloadOnly()方法也是可以替换into()方法的,不过downloadOnly()方法的用法明显要比preload()方法复杂不少。顾名思义,downloadOnly()方法表示只会下载图片,而不会对图片进行加载。当图片下载完成之后,我们可以得到图片的存储路径,以便后续进行操作。

downloadOnly()方法是定义在DrawableTypeRequest类当中的,它有两个方法重载,一个接收图片的宽度和高度,另一个接收一个泛型对象,如下所示:

downloadOnly(int width, int height):子线程

downloadOnly(Y target):UI线程

这两个方法各自有各自的应用场景,其中downloadOnly(int width, int height)是用于在子线程中下载图片的,而downloadOnly(Y target)是用于在主线程中下载图片的。

downloadOnly(int width, int height):子线程

public void downloadImage() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                String url = "XXX";
                final Context context = getApplicationContext();
                FutureTarget<File> target = Glide.with(context)
                        .load(url)
                        .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
                final File imageFile = target.get();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, imageFile.getPath(), Toast.LENGTH_LONG).show();
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
}

如上,downloadOnly()方法会返回一个FutureTarget对象,这个时候其实Glide已经开始在后台下载图片了,我们随时都可以调用FutureTarget的get()方法来获取下载的图片文件,只不过如果图片还没下载好线程会暂时阻塞住,等下载完成了才会把图片的File对象返回。这样我们就能清晰地看出来图片完整的缓存路径是什么了。

 

之后我们可以使用如下代码去加载这张图片,图片就会立即显示出来,而不用再去网络上请求了。

 ImageView imageview=findViewById(R.id.activity_listview_imageview);
 Glide.with(this)
      .load("XXX")
      .diskCacheStrategy(DiskCacheStrategy.SOURCE)
      .error(R.mipmap.za)
      .placeholder(R.mipmap.patient_ava)
      .into(imageview);

需要注意的是,这里必须将硬盘缓存策略指定成DiskCacheStrategy.SOURCE或者DiskCacheStrategy.ALL,否则Glide将无法使用我们刚才下载好的图片缓存文件。

其实downloadOnly(int width, int height)方法必须使用在子线程当中,最主要还是因为它在内部帮我们自动创建了一个RequestFutureTarget,是这个RequestFutureTarget要求必须在子线程当中执行。而downloadOnly(Y target)方法则要求我们传入一个自己创建的Target,因此就不受RequestFutureTarget的限制了。

 

 

downloadOnly(Y target):UI线程

public class DownloadImageTarget implements Target<File> {


    @Override
    public void onStart() {
    }

    @Override
    public void onStop() {
    }

    @Override
    public void onDestroy() {
    }

    @Override
    public void onLoadStarted(Drawable placeholder) {
    }

    @Override
    public void onLoadFailed(Exception e, Drawable errorDrawable) {
    }

    @Override
    public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {
        Log.d(TAG, resource.getPath());
    }

    @Override
    public void onLoadCleared(Drawable placeholder) {
    }

    @Override
    public void getSize(SizeReadyCallback cb) {
        cb.onSizeReady(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
    }

    @Override
    public void setRequest(Request request) {
    }

    @Override
    public Request getRequest() {
        return null;
    }
}

 

ImageView imageview=findViewById(R.id.activity_listview_imageview);
Glide.with(this)
     .load("XXX")
     .downloadOnly(new DownloadImageTarget());

 

 

 

20.各种操作监听

Glide的各种操作监听即listener()方法。listener()方法的作用非常普遍,它可以用来监听Glide加载图片的状态。比如现在使用了preload()方法来对图片进行预加载,但是我怎样确定预加载有没有完成呢?还有如果Glide加载图片失败了,我该怎样调试错误的原因呢?答案都在listener()方法当中。listener()是结合into()方法一起使用的,当然也可以结合preload()方法一起使用。

 

RequestListener对象

private RequestListener<String, GlideDrawable> requestListener=new RequestListener<String, GlideDrawable>() {
        @Override
        public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
            Log.d("TAG","onException方法执行!");
            return false;
        }

        @Override
        public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
            Log.d("TAG","onResourceReady方法执行!");
            return false;
        }
    };

 

获取图片

ImageView imageview=findViewById(R.id.activity_listview_imageview);
Glide.with(this)
     .load("XXX")
     .listener(requestListener)
     .error(R.mipmap.za)
     .placeholder(R.mipmap.patient_ava)
     .into(imageview);

 

说明

RequestListener接口需要实现两个方法,一个onResourceReady()方法,一个onException()方法。

onResourceReady():图片加载完成。

onException():图片加载失败。且此方法会将失败的Exception参数传进来,这样我们就可以定位具体失败的原因了。

onResourceReady()方法和onException()方法都有一个布尔值的返回值,返回false就表示这个事件没有被处理,还会继续向下传递,返回true就表示这个事件已经被处理掉了,从而不会再继续向下传递。举个简单点的例子,如果我们在RequestListener的onResourceReady()方法中返回了true,那么就不会再回调Target的onResourceReady()方法了。

 

 

 

21.几个常用的方法。(ListView 等View使用时)

<1> 当列表滑动停止时,调用resumeRequests()恢复请求。

Glide.with(this).resumeRequests();

 

<2> 当列表在滑动的时候,调用pauseRequests()取消请求。

Glide.with(this).pauseRequests();

 

<3> 清除掉所有的图片加载请求。

 

 

 

 

附1:GlideV4版本详解:Android 图片库之Glide框架之V3版本和V4版本区别

 

 

 

附2:Glide与Picasso对比

原文:http://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en

译文:http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0327/2650.html

 

 

 

附3:Glide框架GitHub链接

https://github.com/bumptech/glide

 

 

附4:几种图片框架对比图

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值