Android 图片加载(二)图片加载框架Glide 入门篇

原文链接:http://bumptech.github.io/glide/
Github地址:https://github.com/bumptech/glide

上一篇:Android 图片加载(一)高效加载Bitmap 基础篇


一、Glide简介

Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道decode pipeline,以及自动的资源池技术。

Android 图片加载(二)图片加载框架Glide 入门篇_第1张图片

Glide支持拉取、解码和展示视频快照,图片和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。

虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。

(1)API设计

Glide使用简明的流式语法API,几行代码就能轻松实现图片加载。

Glide.with(this)
        .load(url)
        .into(imageView);

(2)性能

Glide充分考虑到Android图片加载性能的两个关键方面:

  • 图片解码速度
  • 解码图片带来的资源压力

为了让用户拥有良好的App使用体验,图片不仅要快速加载,而且还不能因为过多的主线程I/O或频繁的垃圾回收导致页面的闪烁和抖动现象。

Glide使用了多个步骤来确保在Android上加载图片尽可能的快速和平滑:

  • 自动、智能地下采样(downsampling)和缓存(caching),以最小化存储开销和解码次数;
  • 积极的资源重用,例如字节数组和Bitmap,以最小化昂贵的垃圾回收和堆碎片影响;
  • 深度的生命周期集成,以确保仅优先处理活跃的Fragment和Activity的请求,并有利于应用在必要时释放资源以避免在后台时被杀掉。

二、集成与使用

(1)Gradle集成

如果使用 Gradle,可从 Maven Central 或 JCenter 中添加对 Glide 的依赖。同样,你还需要添加 Android 支持库的依赖。

repositories {
  mavenCentral()
  maven { url 'https://maven.google.com' }
}
dependencies {
    compile 'com.github.bumptech.glide:glide:4.8.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
}

注意:如果可能,请尽量在你的依赖中避免使用 @aar 。如果你必须这么做,请添加 transitive=true 以确保所有必要的类都被包含到你的 API 中:

dependencies {
    implementation ("com.github.bumptech.glide:glide:4.8.0@aar") {
        transitive = true
    }
}

在 Gradle 中,@aar 意味着 “Artifact Only”,默认情况下将排除所有依赖。

如果你有使用到 proguard,那么请把以下代码添加到你的 proguard.cfg 文件中:

-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

如果你的 target API 低于 Android API 27,请添加:

-dontwarn com.bumptech.glide.load.resource.bitmap.VideoDecoder

VideoDecoder 使用 API 27 的一些接口,这可能导致 proguard 发出警告,尽管这些 API 在旧版 Android 设备上根本不会被调用。
如果你使用 DexGuard 你可能还需要添加:

# for DexGuard only
-keepresourcexmlelements manifest/application/meta-data@value=GlideModule

(2)基本用法

我们只需使用几行代码就能轻松实现图片加载:

Glide.with(this)
//        .asGif() //加载GIF动图
        .load(IMAGE_URL)
        .into(imageView);

注:asGif只能加载gif动态图片,加载其他图片报错

我们也可以使用clear()方法取消图片加载:

Glide.with(this).clear(imageView);

实际上,当 Glide.with()中传入的 Activity 或 Fragment 实例销毁时,Glide会自动取消加载并回收资源。

(3)非 View 目标

除了将 BitmapDrawable 加载到 View 之外,你也可以开始异步加载到你的自定义 Target 中:

Glide.with(this)
        .load("https://i9.hexun.com/2018-11-24/195299307.jpg")
        .fitCenter()
        .placeholder(R.drawable.leaf)  //占位符
        .into(new SimpleTarget() {
            @Override
            public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) {
                imageView.setImageDrawable(resource);
            }
        });

(4)后台线程

如果需要在后台线程加载图片,可以使用 submit(int, int)

new LoadTask().execute(IMAGE_URL);

private class LoadTask extends AsyncTask {

    @Override
    protected Drawable doInBackground(String... strings) {
        FutureTarget futureTarget = Glide.with(GlideActivity.this)
                .load(strings[0])
                .fitCenter()
                .placeholder(R.drawable.ic_launcher_foreground)
                .submit(400,400);
        try {
            return futureTarget.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Drawable drawable) {
        super.onPostExecute(drawable);
        imageView.setImageDrawable(drawable);
    }
}

如果你不想让 BitmapDrawable 自身在后台线程中,你也可以使用和前台线程一样的方式来开始异步加载:

Glide.with(context)
  .asBitmap()
  .load(url)
  .into(new Target() {
    ...
  });

(5)其他常用配置

1、占位符

Glide允许用户指定三种不同类型的占位符,分别在三种不同场景使用:

  • placeholder
    当请求正在执行时被展示的。当请求成功完成时,占位符会被请求到的资源替换。如果被请求的资源是从内存中加载出来的,那么占位符可能根本不会被显示。如果请求失败并且没有设置error,则占位符将被持续展示。类似地,如果请求的url/model为 null ,并且errorfallback都没有设置,那么占位符也会继续显示。
public static final String IMAGE_URL = "https://i9.hexun.com/2018-11-24/195299307.jpg";
Glide.with(this)
        .load(IMAGE_URL)
        .placeholder(R.drawable.leaf) //占位符
        .into(imageView);
  • error
    在请求永久性失败时展示。同样也在请求的url/model为 null ,且没有设置 fallback 时展示。
public static final String IMAGE_URL = "123";
Glide.with(this)
        .load(IMAGE_URL)
        .error(R.drawable.ic_launcher_background) //错误符
        .into(imageView);
  • fallback
    在请求的url/model为 null 时展示。设计fallback的主要目的是允许用户指示 null 是否为可接受的正常情况。例如,一个 null 的个人资料 url 可能暗示这个用户没有设置头像,因此应该使用默认头像。 默认情况下Glide将 null 作为错误处理,所以可以接受 null 的应用应当显式地设置一个fallback Drawable
public static final String IMAGE_URL = null;
Glide.with(this)
        .load(IMAGE_URL)
        .fallback(R.drawable.ic_launcher_background) //错误符
        .into(imageView);

有几点需要注意:

  1. 占位符是在主线程从Android Resources加载的。
  2. Transformation仅被应用于被请求的资源,而不会对任何占位符使用。
  3. 对于有状态的 Drawable来说,多个View在同一时刻展示它们通常是不安全的,因为多个View可能会同时修改一个Drawable的状态信息。
2、请求选项

Glide中的大部分设置项都可以通过 RequestOptions 类和 apply() 方法来应用到程序中。

RequestOptions requestOptions = new RequestOptions()
        .centerCrop()  //设置scaleType
        .skipMemoryCache(false) //内存缓存
        .diskCacheStrategy(DiskCacheStrategy.ALL) //存储缓存策略
        .error(R.drawable.ic_launcher_background); //错误符
Glide.with(this)
        .load(IMAGE_URL)
        .apply(requestOptions) //配置请求选项
        .into(imageView);

apply()方法可以被调用多次,因此 RequestOption 可以被组合使用。如果 RequestOptions 对象之间存在相互冲突的设置,那么只有最后一个被应用的 RequestOptions 会生效。

3、过渡选项

TransitionOptions用于决定你的加载完成时会发生什么。使用 TransitionOption 可以应用以下变换:

  • View淡入
  • 与占位符交叉淡入
  • 或者什么都不发生

如果不使用变换,你的图像将会直接“跳入”其显示位置,替换掉之前的图像。为了避免这种突然的改变,你可以淡入view,或者让多个Drawable交叉淡入,而这些都需要使用TransitionOptions完成。

例如,要应用一个简单的交叉淡入变换:

Glide.with(this)
        .load(IMAGE_URL)
        .placeholder(R.drawable.ic_launcher_background)
        .transition(DrawableTransitionOptions.withCrossFade(1000)) //配置过渡选项
        .into(imageView);

不同于RequestOptionsTransitionOptions是特定资源类型独有的,你能使用的变换取决于你让Glide加载哪种类型的资源。
这样的结果是,假如你请求加载一个 Bitmap ,你需要使用 BitmapTransitionOptions ,而不是 DrawableTransitionOptions 。同样,当你请求加载 Bitmap时,你只需要做简单的淡入,而不需要做复杂的交叉淡入。

4、缩略图请求

Glide 的 thumbnail() API 允许你指定一个 RequestBuilder 与你的主请求并行启动。thumbnail()会在主请求加载过程中展示,如果主请求在缩略图请求之前完成,则缩略图请求中的图像将不会被展示。thumbnail()对本地和远程图片都适用,尤其是当低分辨率缩略图存在于 Glide 的磁盘缓存时,它们将很快被加载出来。

RequestBuilder thumbnailRequest = Glide.with(this).load(R.drawable.ic_launcher_background);
Glide.with(this)
        .load(IMAGE_URL)
        .thumbnail(thumbnailRequest)
        .into(imageView);

只要你的 thumbnailUrl 指向的图片比你的主 url 的分辨率更低,它将会很好地工作。使用override强制 Glide 在缩略图请求中加载一个低分辨率图像:

RequestBuilder thumbnailRequest = Glide.with(this)
        .load(IMAGE_URL).override(100);
Glide.with(this)
        .load(IMAGE_URL)
        .thumbnail(thumbnailRequest)
        .into(imageView);

thumbnail()方法还有一个简化版本,它只需要一个 sizeMultiplier 参数。如果你只是想为你的加载相同的图片,但尺寸为 ViewTarget 的某个百分比的话特别有用:

Glide.with(this)
        .load(IMAGE_URL)
        .thumbnail(0.5f)
        .into(imageView);
5、失败时开始新的请求

从 Glide 4.3.0 开始,可以使用 error API 来指定一个RequestBuilder,以在主请求失败时开始一次新的加载。

//请求空串失败后加载IMAGE_URL
RequestBuilder thumbnailRequest = Glide.with(this)
        .load(IMAGE_URL).override(100);
Glide.with(this)
        .load("") 
        .error(thumbnailRequest)
        .into(imageView);

如果主请求成功完成,这个error RequestBuilder 将不会被启动。如果你同时指定了一个 thumbnail() 和一个 error() RequestBuilder,则这个后备的RequestBuilder将在主请求失败时启动,即使缩略图请求成功也是如此。


下一篇:Android 图片加载(三)图片加载框架Glide 进阶篇

你可能感兴趣的:(Android 图片加载(二)图片加载框架Glide 入门篇)