关于 Glide
Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。
Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。
虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。
Glide配置
如果使用 Gradle,可从 Maven Central 或 JCenter 中添加对 Glide 的依赖。同样,你还需要添加 Android 支持库的依赖。
dependencies {
compile 'com.github.bumptech.glide:glide:4.3.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.3.1'
}
repositories {
mavenCentral()
maven { url 'https://maven.google.com' }
}
加权限
Glide 假定你要访问的数据都存储在你的应用中,不要求任何权限。也就是说,大部分应用从设备上(DCIM,图库,或SD卡的其他地方)或 Internet 上加载图片。因此,你可能需要包含一条或多条以下列出的权限,这取决于你的应用场景。
Internet
如果你计划从 URL 或一个网络连接中加载数据,你需要添加 INTERNET
和 ACCESS_NETWORK_STATE
权限到你的 AndroidManifest.xml
中:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="your.package.name"
<uses-permission android:name="android.permission.INTERNET"/>
<!--
Allows Glide to monitor connectivity status and restart failed requests if users go from a
a disconnected to a connected network state.
-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application>
...
</application>
</manifest>
从技术上讲,ACCESS_NETWORK_STATE
对于 Glide 加载 URL 并不是必需的,但是它将帮助 Glide 处理 片状网络(flaky network) 和飞行模式。请继续阅读下面的连接监视章节以了解详情。
连接监听 (Connectivity Monitoring)
如果你正在从 URL 加载图片,Glide 可以自动帮助你处理片状网络连接:它可以监听用户的连接状态并在用户重新连接到网络时重启之前失败的请求。如果 Glide 检测到你的应用拥有 ACCESS_NETWORK_STATUS
权限,Glide 将自动监听连接状态而不需要额外的改动。
你可以通过检查 ConnectivityMonitor
日志标签来验证 Glide 是否正在监听网络状态:
adb shell setprop log.tag.ConnectivityMonitor DEBUG
如果你成功添加了 ACCESS_NETWORK_STATUS
权限,你将在 logcat 中看到类似这样的日志:
11-18 18:51:23.673 D/ConnectivityMonitor(16236): ACCESS_NETWORK_STATE permission granted, registering connectivity monitor
11-18 18:48:55.135 V/ConnectivityMonitor(15773): connectivity changed: false
11-18 18:49:00.701 V/ConnectivityMonitor(15773): connectivity changed: true
而如果权限缺失,你将看到一条错误:
11-18 18:51:23.673 D/ConnectivityMonitor(16236): ACCESS_NETWORK_STATE permission missing, cannot register connectivity monitor
本地存储 (Local Storage)
要从本地文件夹或 DCIM 或图库中加载图片,你将需要添加 READ_EXTERNAL_STORAGE
权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="your.package.name"
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application>
...
</application>
</manifest>
而如果要使用 ExternalPreferredCacheDiskCacheFactory
来将 Glide 的缓存存储到公有 SD 卡上,你还需要添加 WRITE_EXTERNAL_STORAGE
权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="your.package.name"
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
...
</application>
</manifest>
Proguard(就是代码混淆)
如果你有使用到 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.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
基本用法
多数情况下,使用Glide加载图片非常简单,一行代码足矣:
Glide.with(fragment)//所在fragment
.load(myUrl)//网络请求加载图片地址
.into(imageView);//imageView
取消加载同样很简单:
Glide.with(fragment).clear(imageView);
尽管及时取消不必要的加载是很好的实践,但这并不是必须的操作。实际上,当 [Glide.with()
] 中传入的 Activity 或 Fragment 实例销毁时,Glide 会自动取消加载并回收资源。
在 Application 模块中的使用
在 Application 模块中,可创建一个添加有 @GlideModule
注解,继承自 AppGlideModule
的类。此类可生成出一个流式 API,内联了多种选项,和集成库中自定义的选项:
package com.example.myapp;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;
@GlideModule
public final class MyAppGlideModule extends AppGlideModule {}
生成的 API 默认名为 GlideApp
,与 [AppGlideModule
]的子类包名相同。在 Application 模块中将 Glide.with()
替换为 GlideApp.with()
,即可使用该 API 去完成加载工作。
GlideApp.with(fragment)
.load(myUrl)
.placeholder(placeholder)
.fitCenter()
.into(imageView);
在 ListView 和 RecyclerView 中的使用
在 ListView 或 RecyclerView 中加载图片的代码和在单独的 View 中加载完全一样。Glide 已经自动处理了 View 的复用和请求的取消:
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
String url = urls.get(position);
Glide.with(fragment)
.load(url)
.into(holder.imageView);
}
对 url 进行 null 检验并不是必须的,如果 url 为 null,Glide 会清空 View 的内容,或者显示 placeholder Drawable 或 fallback Drawable 的内容。
Glide 唯一的要求是,对于任何可复用的 View
或 [Target
],如果它们在之前的位置上,用 Glide 进行过加载操作,那么在新的位置上要去执行一个新的加载操作,或调用 [clear()
] API 停止 Glide 的工作。
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (isImagePosition(position)) {
String url = urls.get(position);
Glide.with(fragment)
.load(url)
.into(holder.imageView);
} else {
Glide.with(fragment).clear(holder.imageView);
holder.imageView.setImageDrawable(specialDrawable);
}
}
对 View
调用 [clear()
] 或 into(View)
,表明在此之前的加载操作会被取消,并且在方法调用完成后,Glide 不会改变 view 的内容。如果你忘记调用 [clear()
],而又没有开启新的加载操作,那么就会出现这种情况,你已经为一个 view 设置好了一个 Drawable
,但该 view 在之前的位置上使用 Glide 进行过加载图片的操作,Glide 加载完毕后可能会将这个 view 改回成原来的内容。
这里的代码以 RecyclerView 的使用为例,但规则同样适用于 ListView。
非 View 目标
除了将 Bitmap
和 Drawable
加载到 View
之外,你也可以开始异步加载到你的自定义 Target
中:
Glide.with(context
.load(url)
.into(new SimpleTarget<Drawable>() {
@Override
public void onResourceReady(Drawable resource, Transition<Drawable> transition) {
// Do something with the Drawable here.
}
});
后台线程
在后台线程加载图片也是直接使用 [submit(int, int)
]:
FutureTarget<Bitmap> futureTarget =
Glide.with(context)
.asBitmap()
.load(url)
.submit(width, height);
Bitmap bitmap = futureTarget.get();
// Do something with the Bitmap and then when you're done with it:
Glide.with(context).clear(futureTarget);
如果你不想让 Bitmap
和 Drawable
自身在后台线程中,你也可以使用和前台线程一样的方式来开始异步加载:
Glide.with(context)
.asBitmap()
.load(url)
.into(new Target<Bitmap>() {
...
});
占位符
Glide允许用户指定三种不同类型的占位符,分别在三种不同场景使用:
- placeholder
- error
- fallback
占位符(Placeholder)
占位符是当请求正在执行时被展示的 Drawable 。当请求成功完成时,占位符会被请求到的资源替换。如果被请求的资源是从内存中加载出来的,那么占位符可能根本不会被显示。如果请求失败并且没有设置 error Drawable
,则占位符将被持续展示。类似地,如果请求的url/model为 null
,并且 error Drawable
和 fallback
都没有设置,那么占位符也会继续显示。
使用 generated API:
GlideApp.with(fragment)
.load(url)
.placeholder(R.drawable.placeholder)
.into(view);
Or:
GlideApp.with(fragment)
.load(url)
.placeholder(new ColorDrawable(Color.BLACK))
.into(view);
错误符(Error)
error Drawable
在请求永久性失败时展示。error Drawable
同样也在请求的url/model为 null
,且并没有设置 fallback Drawable
时展示。
With the generated API:
GlideApp.with(fragment)
.load(url)
.error(R.drawable.error)
.into(view);
Or:
GlideApp.with(fragment)
.load(url)
.error(new ColorDrawable(Color.RED))
.into(view);
后备回调符(Fallback)
fallback Drawable
在请求的url/model为 null
时展示。设计 fallback Drawable
的主要目的是允许用户指示 null
是否为可接受的正常情况。例如,一个 null
的个人资料 url 可能暗示这个用户没有设置头像,因此应该使用默认头像。然而,null
也可能表明这个元数据根本就是不合法的,或者取不到。 默认情况下Glide将 null
作为错误处理,所以可以接受 null
的应用应当显式地设置一个 fallback Drawable
。
使用 generated API:
GlideApp.with(fragment)
.load(url)
.fallback(R.drawable.fallback)
.into(view);
Or:
GlideApp.with(fragment)
.load(url)
.fallback(new ColorDrawable(Color.GREY))
.into(view);
选项
请求选项
Glide中的大部分设置项都可以通过 RequestOptions
类和 apply()
方法来应用到程序中。
使用 request options
可以实现(包括但不限于):
- 占位符(
Placeholders
) - 转换(
Transformations
) - 缓存策略(
Caching Strategies
) - 组件特有的设置项,例如编码质量,或
Bitmap
的解码配置等。
例如,要应用一个 CenterCrop
转换,你可以使用以下代码:
import static com.bumptech.glide.request.RequestOptions.centerCropTransform;
Glide.with(fragment)
.load(url)
.apply(centerCropTransform(context))
.into(imageView);
在这个例子中使用了对 RequestOptions
类里的方法的静态import,这会让代码看起来更简洁流畅。
如果你想让你的应用的不同部分之间共享相同的加载选项,你也可以初始化一个新的 RequestOptions
对象,并在每次加载时传入这个对象:
RequestOptions cropOptions = new RequestOptions().centerCrop(context);
...
Glide.with(fragment)
.load(url)
.apply(cropOptions)
.into(imageView);
apply()
方法可以被调用多次,因此 RequestOption
可以被组合使用。如果 RequestOptions
对象之间存在相互冲突的设置,那么只有最后一个被应用的 RequestOptions
会生效。
Generated API
如果你正在使用 Generated API , 所有的 请求选项
方法都会被内联并可以直接使用:
GlideApp.with(fragment)
.load(url)
.centerCrop()
.into(imageView);
过渡选项
TransitionOptions 用于决定你的加载完成时会发生什么。
使用 TransitionOption
可以应用以下变换:
- View淡入
- 与占位符交叉淡入
- 或者什么都不发生
如果不使用变换,你的图像将会“跳入”其显示位置,直接替换掉之前的图像。为了避免这种突然的改变,你可以淡入view,或者让多个Drawable交叉淡入,而这些都需要使用TransitionOptions
完成。
例如,要应用一个交叉淡入变换:
import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;
Glide.with(fragment)
.load(url)
.transition(withCrossFade())
.into(view);
不同于RequestOptions
,TransitionOptions
是特定资源类型独有的,你能使用的变换取决于你让Glide加载哪种类型的资源。
这样的结果是,假如你请求加载一个 Bitmap
,你需要使用 BitmapTransitionOptions ,而不是 DrawableTransitionOptions 。同样,当你请求加载 Bitmap
时,你只需要做简单的淡入,而不需要做复杂的交叉淡入。
RequestBuilder
RequestBuilder 是Glide中请求的骨架,负责携带请求的url和你的设置项来开始一个新的加载过程。
使用 RequestBuilder
可以指定:
- 你想加载的资源类型(Bitmap, Drawable, 或其他)
- 你要加载的资源地址(url/model)
- 你想最终加载到的View
- 任何你想应用的(一个或多个)
RequestOption
对象 - 任何你想应用的(一个或多个)
TransitionOption
对象 - 任何你想加载的缩略图
thumbnail()
你可以通过调用 Glide.with()
来构造一个 RequestBuilder
对象,然后使用某一个 as
方法:
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment).asDrawable();
或使用 Glide.with()
然后 load()
:
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment).load(url);
选择资源类型
RequestBuilders
是特定于它们将要加载的资源类型的。默认情况下你会得到一个 Drawable RequestBuilder ,但你可以使用 as...
系列方法来改变请求类型。例如,如果你调用了 asBitmap()
,你就将获得一个 Bitmap``RequestBuilder
对象,而不是默认的 Drawable RequestBuilder。
RequestBuilder<Bitmap> requestBuilder = Glide.with(fragment).asBitmap();
应用 RequestOptions
前面提到,可以使用 apply()
方法应用 RequestOptions
,使用 transition()
方法应用 TransitionOptions
。
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment).asDrawable();
requestBuilder.apply(requestOptions);
requestBuilder.transition(transitionOptions);
RequestBuilder 也可以被复用于开始多个请求:
RequestBuilder<Drawable> requestBuilder =
Glide.with(fragment)
.asDrawable()
.apply(requestOptions);
for (int i = 0; i < numViews; i++) {
ImageView view = viewGroup.getChildAt(i);
String url = urls.get(i);
requestBuilder.load(url).into(view);
}
缩略图 (Thumbnail) 请求
Glide 的 thumbnail
API 允许你指定一个 RequestBuilder
以与你的主请求并行启动。缩略图
会在主请求加载过程中展示。如果主请求在缩略图请求之前完成,则缩略图请求中的图像将不会被展示。[thumbnail
] API 允许你简单快速地加载图像的低分辨率版本,并且同时加载图像的无损版本,这可以减少用户盯着加载指示器 【例如进度条–译者注)】 的时间。
thumbnail()
API 对本地和远程图片都适用,尤其是当低分辨率缩略图存在于 Glide 的磁盘缓存时,它们将很快被加载出来。
thumbnail
API 使用起来相对简单:
Glide.with(fragment)
.load(url)
.thumbnail(Glide.with(fragment)
.load(thumbnailUrl))
.into(imageView);
只要你的 thumbnailUrl
指向的图片比你的主 url
的分辨率更低,它将会很好地工作。相当数量的加载 API 提供了不同的指定图片尺寸的方法,它们尤其适用于 thumbnail
API。
如果你仅仅想加载一个本地图像,或者你只有一个单独的远程 URL, 你仍然可以从缩略图 API 受益。请使用 Glide 的 override
或 sizeMultiplier
API 来强制 Glide 在缩略图请求中加载一个低分辨率图像:
int thumbnailSize = ...;
Glide.with(fragment)
.load(localUri)
.thumbnail(Glide.with(fragment)
.load(localUri)
.override(thumbnailSize))
.into(view);
thumbnail
方法有一个简化版本,它只需要一个 sizeMultiplier
参数。如果你只是想为你的加载相同的图片,但尺寸为 View
或 Target
的某个百分比的话特别有用:
Glide.with(fragment)
.load(localUri)
.thumbnail(/*sizeMultiplier=*/ 0.25f)
.into(imageView);
在失败时开始新的请求
从 Glide 4.3.0 开始,你现在可以使用 error
API 来指定一个 RequestBuilder
,以在主请求失败时开始一次新的加载。例如,在请求 primaryUrl
失败后加载 fallbackUrl
:
Glide.with(fragment)
.load(primaryUrl)
.error(Glide.with(fragment)
.load(fallbackUrl))
.into(imageView);
如果主请求成功完成,这个error RequestBuilder
将不会被启动。如果你同时指定了一个 thumbnail
和一个 error
RequestBuilder
,则这个后备的 RequestBuilder
将在主请求失败时启动,即使缩略图请求成功也是如此。
组件选项
Option
类是给Glide的组件添加参数的通用办法,包括 ModelLoaders
, ResourceDecoders
, ResourceEncoders
, Encoders
等等。一些Glide的内置组件提供了设置项,自定义的组件也可以添加设置项。
Option
通过 RequestOptions
类应用到请求上:
import static com.bumptech.glide.request.RequestOptions.option;
Glide.with(context)
.load(url)
.apply(option(MyCustomModelLoader.TIMEOUT_MS, 1000L))
.into(imageView);
你也可以创建一个全新的 RequestOptions 对象:
RequestOptions options = new RequestOptions()
.set(MyCustomModelLoader.TIMEOUT_MS, 1000L);
Glide.with(context)
.load(url)
.apply(options)
.into(imageView);
或者使用 Generated API:
GlideApp.with(context)
.load(url)
.set(MyCustomModelLoader.TIMEOUT_MS, 1000L)
.into(imageView);
变换
在Glide中,Transformations 可以获取资源并修改它,然后返回被修改后的资源。通常变换操作是用来完成剪裁或对位图应用过滤器,但它也可以用于转换GIF动画,甚至自定义的资源类型。
内置类型
Glide 提供了很多内置的变换,包括:
- CenterCrop
- FitCenter
- CircleCrop
默认变换
RequestOptions options = new RequestOptions();
options.centerCrop();
Glide.with(fragment)
.load(url)
.apply(options)
.into(imageView);
大多数内置的变换都有静态的 import ,这是为 API 的流畅性考虑的。例如,你可以通过静态方法应用一个 FitCenter 变换:
import static com.bumptech.glide.request.RequestOptions.fitCenterTransform;
Glide.with(fragment)
.load(url)
.apply(fitCenterTransform())
.into(imageView);
如果你正在使用 Generated API ,那么这些变换方法已经被内联了,所以使用起来甚至更为轻松:
GlideApp.with(fragment)
.load(url)
.fitCenter()
.into(imageView);
多重变换
默认情况下,每个 transform()
调用,或任何特定转换方法(fitCenter()
, centerCrop()
, bitmapTransform()
etc)的调用都会替换掉之前的变换。
如果你想在单次加载中应用多个变换,请使用 MultiTransformation
类。
使用 generated API:
Glide.with(fragment)
.load(url)
.transform(new MultiTransformation(new FitCenter(), new YourCustomTransformation())
.into(imageView);
或结合使用快捷方法和 generated API:
GlideApp.with(fragment)
.load(url)
.transforms(new FitCenter(), new YourCustomTransformation())
.into(imageView);
请注意,你向 MultiTransformation
的构造器传入变换参数的顺序,决定了这些变换的应用顺序。
定制变换
尽管 Glide 提供了各种各样的内置 Transformation
实现,如果你需要额外的功能,你也可以实现你自己的 Transformation
。
BitmapTransformation
如果你只需要变换 Bitmap
,最好是从继承 BitmapTransformation
开始。BitmapTransformation
处理了一些基础的东西,包括提取和回收原始的 Bitmap,如果你的变换返回了一个新修改的 Bitmap 的话。
一个简单的实现看起来可能像这样:
public class FillSpace extends BitmapTransformation {
private static final String ID = "com.bumptech.glide.transformations.FillSpace";
private static final String ID_BYTES = ID.getBytes(STRING_CHARSET_NAME);
{@literal @Override}
public Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
if (toTransform.getWidth() == outWidth && toTransform.getHeight() == outHeight) {
return toTransform;
}
return Bitmap.createScaledBitmap(toTransform, outWidth, outHeight, /*filter=*/ true);
}
{@literal @Override}
public void equals(Object o) {
return o instanceof FillSpace;
}
{@literal @Override}
public int hashCode() {
return ID.hashCode();
}
{@literal @Override}
public void updateDiskCacheKey(MessageDigest messageDigest)
throws UnsupportedEncodingException {
messageDigest.update(ID_BYTES);
}
}
尽管你的 Transformation
将几乎确定比这个示例更复杂,但它应该包含了相同的基本元素和复写方法。
必需的方法
请特别注意,对于任何 Transformation
子类,包括 BitmapTransformation
,你都有三个方法你 必须 实现它们,以使得磁盘和内存缓存正确地工作:
equals()
hashCode()
updateDiskCacheKey
如果你的 Transformation
没有参数,通常使用一个包含完整包限定名的 static
final
String
来作为一个 ID,它可以构成 hashCode()
的基础,并可用于更新 updateDiskCacheKey()
传入的 MessageDigest
。如果你的 Transformation
需要参数而且它会影响到 Bitmap
被变换的方式,它们也必须被包含到这三个方法中。
例如,Glide 的 RoundedCorners
变换接受一个 int
,它决定了圆角的弧度。它的equals()
, hashCode()
和 updateDiskCacheKey
实现看起来像这样:
@Override
public boolean equals(Object o) {
if (o instanceof RoundedCorners) {
RoundedCorners other = (RoundedCorners) o;
return roundingRadius == other.roundingRadius;
}
return false;
}
@Override
public int hashCode() {
return Util.hashCode(ID.hashCode(),
Util.hashCode(roundingRadius));
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
messageDigest.update(ID_BYTES);
byte[] radiusData = ByteBuffer.allocate(4).putInt(roundingRadius).array();
messageDigest.update(radiusData);
}
原来的 String
仍然保留,但 roundingRadius
被包含到了三个方法中。这里,updateDiskCacheKey
方法还演示了你可以如何使用 ByteBuffer
来包含基本参数到你的 updateDiskCacheKey
实现中。
不要忘记 equals() / hashCode()
值得重申的一点是,为了让内存缓存正常地工作你是否必须实现 equals()
和 hashCode()
方法。很不幸,即使你没有复写这两个方法,BitmapTransformation
和 Transformation
也能通过编译,但这并不意味着它们能正常工作。
Glide里的缓存
默认情况下,Glide 会在开始一个新的图片请求之前检查以下多级的缓存:
- 活动资源 (Active Resources) - 现在是否有另一个 View 正在展示这张图片?
- 内存缓存 (Memory cache) - 该图片是否最近被加载过并仍存在于内存中?
- 资源类型(Resource) - 该图片是否之前曾被解码、转换并写入过磁盘缓存?
- 数据来源 (Data) - 构建这个图片的资源是否之前曾被写入过文件缓存?
前两步检查图片是否在内存中,如果是则直接返回图片。后两步则检查图片是否在磁盘上,以便快速但异步地返回图片。
如果四个步骤都未能找到图片,则Glide会返回到原始资源以取回数据(原始文件,Uri, Url等)。
缓存键(Cache Keys)
在 Glide v4 里,所有缓存键都包含至少两个元素:
- 请求加载的 model(File, Url, Url)
- 一个可选的
签名
(Signature)
另外,步骤1-3(活动资源,内存缓存,资源磁盘缓存)的缓存键还包含一些其他数据,包括:
- 宽度和高度
- 可选的
变换(Transformation)
- 额外添加的任何
选项(Options)
- 请求的数据类型 (Bitmap, GIF, 或其他)
活动资源和内存缓存使用的键还和磁盘资源缓存略有不同,以适应内存 选项(Options)
,比如影响 Bitmap 配置的选项或其他解码时才会用到的参数。
为了生成磁盘缓存上的缓存键名称,以上的每个元素会被哈希化以创建一个单独的字符串键名,并在随后作为磁盘缓存上的文件名使用.
配置缓存
Glide 提供一系列的选项,以允许你选择加载请求与 Glide 缓存如何交互。
磁盘缓存策略
DiskCacheStrategy
可被 diskCacheStrategy
方法应用到每一个单独的请求。 目前支持的策略允许你阻止加载过程使用或写入磁盘缓存,选择性地仅缓存无修改的原生数据,或仅缓存变换过的缩略图,或是兼而有之。
默认的策略叫做 AUTOMATIC
,它会尝试对本地和远程图片使用最佳的策略。当你加载远程数据(比如,从URL下载)时,AUTOMATIC
策略仅会存储未被你的加载过程修改过(比如,变换,裁剪–译者注)的原始数据,因为下载远程数据相比调整磁盘上已经存在的数据要昂贵得多。对于本地数据,AUTOMATIC
策略则会仅存储变换过的缩略图,因为即使你需要再次生成另一个尺寸或类型的图片,取回原始数据也很容易。
指定 DiskCacheStrategy
非常容易:
GlideApp.with(fragment)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView);
仅从缓存加载图片
某些情形下,你可能希望只要图片不在缓存中则加载直接失败(比如省流量模式)。如果要完成这个目标,你可以在单个请求的基础上使用 onlyRetrieveFromCache
方法:
GlideApp.with(fragment)
.load(url)
.onlyRetrieveFromCache(true)
.into(imageView);
如果图片在内存缓存或在磁盘缓存中,它会被展示出来。否则只要这个选项被设置为 true ,这次加载会视同失败。
跳过缓存
如果你想确保一个特定的请求跳过磁盘和/或内存缓存(比如,图片验证码 –译者注),Glide 也提供了一些替代方案。
仅跳过内存缓存,请使用 skipMemoryCache()
:
GlideApp.with(fragment)
.load(url)
.skipMemoryCache(true)
.into(view);
仅跳过磁盘缓存,请使用 DiskCacheStrategy.NONE
:
GlideApp.with(fragment)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(view);
这两个选项可以同时使用:
GlideApp.with(fragment)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(view);
虽然提供了这些办法让你跳过缓存,但你通常应该不会想这么做。从缓存中加载一个图片,要比拉取-解码-转换成一张新图片的完整流程快得多。
从v3迁移到v4
选项(Options)
Glide v4 中的一个比较大的改动是Glide库处理选项(centerCrop()
, placeholder()
等)的方式。在 v3 版本中,选项由一系列复杂的异构建造者(multityped builders)单独处理。在新版本中,由一个单一类型的唯一一个建造者接管一系列选项对象。Glide 的generated API进一步简化了这个操作:它会合并传入建造者的选项对象和任何已包含的集成库里的选项,以生成一个流畅的 API。
RequestBuilder
对于这类方法:
listener()
thumbnail()
load()
into()
在 Glide v4 版本中,只存在一个 RequestBuilder
对应一个你正在试图加载的类型(Bitmap
, Drawable
, GifDrawable
等)。 RequestBuilder
可以直接访问对这个加载过程有影响的选项,包括你想加载的数据模型(url, uri等),可能存在的缩略图
请求,以及任何的监听器
。RequestBuilder
也是你使用 into()
或者 preload()
方法开始加载的地方:
RequestBuilder<Drawable> requestBuilder = Glide.with(fragment)
.load(url);
requestBuilder
.thumbnail(Glide.with(fragment)
.load(thumbnailUrl))
.listener(requestListener)
.load(url)
.into(imageView);
请求选项
对于这类方法:
centerCrop()
placeholder()
error()
priority()
diskCacheStrategy()
大部分选项被移动到了一个单独的称为 RequestOptions
的对象中,
RequestOptions options = new RequestOptions()
.centerCrop()
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.priority(Priority.HIGH);
RequestOptions
允许你一次指定一系列的选项,然后对多个加载重用它们:
RequestOptions myOptions = new RequestOptions()
.fitCenter()
.override(100, 100);
Glide.with(fragment)
.load(url)
.apply(myOptions)
.into(drawableView);
Glide.with(fragment)
.asBitmap()
.apply(myOptions)
.load(url)
.into(bitmapView);
变换
Glide v4 里的 Transformations
现在会替换之前设置的任何变换。在 Glide v4 中,如果你想应用超过一个的 Transformation
,你需要使用 transforms()
方法:
Glide.with(fragment)
.load(url)
.apply(new RequestOptions().transforms(new CenterCrop(), new RoundedCorners(20)))
.into(target);
或使用 generated API:
GlideApp.with(fragment)
.load(url)
.transforms(new CenterCrop(), new RoundedCorners(20))
.into(target);
解码格式
在 Glide v3, 默认的 DecodeFormat
是 DecodeFormat.PREFER_RGB_565
,它将使用 [Bitmap.Config.RGB_565
],除非图片包含或可能包含透明像素。对于给定的图片尺寸,RGB_565
只使用 [Bitmap.Config.ARGB_8888
] 一般的内存,但对于特定的图片有明显的画质问题,包括条纹(banding)和着色(tinting)。为了避免RGB_565
的画质问题,Glide 现在默认使用 ARGB_8888
。结果是,图片质量变高了,但内存使用也增加了。
要将 Glide v4 默认的 DecodeFormat
改回 DecodeFormat.PREFER_RGB_565
,请在 AppGlideModule
中应用一个 RequestOption
:
@GlideModule
public final class YourAppGlideModule extends GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
builder.setDefaultRequestOptions(new RequestOptions().format(DecodeFormat.PREFER_RGB_565));
}
}
过渡选项
对于这类方法:
crossFade()
animate()
控制从占位符到图片和/或缩略图到全图的交叉淡入和其他类型变换的选项,被移动到了 TransitionOptions
中。
要应用过渡(之前的动画),请使用下列选项中符合你请求的资源类型的一个:
如果你想移除任何默认的过渡,可以使用 TransitionOptions.dontTransition()
]17 。
过渡动画通过 RequestBuilder
应用到请求上:
Glide.with(fragment)
.load(url)
.transition(withCrossFade(R.anim.fade_in, 300));
交叉淡入 (Cross fade)
不同于 Glide v3,Glide v4 将不会默认应用交叉淡入或任何其他的过渡效果。每个请求必须手动应用过渡。
要为一个特定的加载应用一个交叉淡入变换效果,你可以使用:
import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;
Glide.with(fragment)
.load(url)
.transition(withCrossFade())
.into(imageView);
或:
Glide.with(fragment)
.load(url)
.transition(
new DrawableTransitionOptions
.crossFade())
.into(imageView);
Generated API
为了让使用 Glide v4 更简单轻松,Glide 现在也提供了一套可以为应用定制化生成的 API。应用可以通过包含一个标记了 [AppGlideModule
][2 的实现来访问生成的 API。
Generated API添加了一个 GlideApp
类,该类提供了对 RequestBuilder
和 RequestOptions
子类的访问。RequestOptions
的子类包含了所有 RequestOptions
中的方法,以及 GlideExtensions
中定义的方法。RequestBuilder
的子类则提供了生成的 RequestOptions
中所有方法的访问,而不需要你再手动调用 apply
。举个例子:
在没有使用 Generated API 时,请求大概长这样:
Glide.with(fragment)
.load(url)
.apply(centerCropTransform()
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.priority(Priority.HIGH))
.into(imageView);
使用 Generated API,RequestOptions
的调用可以被内联:
GlideApp.with(fragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.priority(Priority.HIGH)
.into(imageView);
你仍然可以使用生成的 RequestOptions
子类来应用相同的选项到多次加载中;但生成的 RequestBuilder
子类可能在多数情况下更为方便。