目标
Glide 中的目标作为请求跟请求者之间的传递者。目标负责显示占位符,加载的资源以及为每个请求确定合适的尺寸。最常用目标是使用 ImageView 显示占位符,Drawable 和 Bitmap 的 ImageViewTarget。用户还可以实现自己的目标,或者对任何可用的基类进行子类化。
指定目标
into(Target) 方法不仅用于启动每个请求,同时也可以指定将要接收请求结果的目标。Glide 提供了一个辅助方法给 into(ImageView) ,其采用 ImageView 并把它包装在目标于适合所请求的资源类型。
为了方便使用自定义目标,这些 into() 方法返回提供给他们的目标:
Target<Bitmap> target = Glide.with(fragment)
.asBitmap()
.load(url)
.into(imageView);
...
// Some time later:
Glide.with(fragment).clear(target);
目标和自动取消
目标可以并且通常应该被重新用于相同的地方显示的每个后续请求。重新使用目标允许 Glide 在新加载启动时自动取消并且重新使用之前负载的资源。未能重新使用目标可能会导致之前请求中的资源替换较新的请求。
自定义目标
重新使用自定义目标的一种简单方法是简单地将其作为实例变量:
private class WidgetHolder {
private final Fragment fragment;
private final Target<Widget> widgetTarget;
public WidgetHolder(Fragment fragment, Widget widget) {
this.fragment = fragment;
widgetTarget = new CustomWidgetTarget(widget);
}
public void showInWidget(Uri uri) {
Glide.with(fragment)
.load(uri)
.into(widgetTarget);
}
}
Glide 能够使用 getRequest() 和 setRequest() 方法查找和取消对目标的请求。这意味着所有自定义的目标都必须实现这些方法。最简单的方法是进行子类化 BaseTarget。
ViewTargets
一些自定义的目标还可以提供更智能的 getRequest() 和 setRequest() 实现,避免严格要求重新使用目标。例如,ViewTarget 使用 Android Framework 的 getTag()和 setTag()方法:
@Override
public Request getRequest() {
return (Request) view.getTag();
}
@Override
public void setRequest(Request request) {
view.setTag(request);
}
由于标签是 View 的属性,因此新加载的 ViewTargets 可以查找和取消/重新使用先前 ViewTargets 的请求。因此,当使用 into(ImageView) 或 ViewTarget 的子类加载到视图中时,您可以为每个加载传递新的目标:
@Override
public void onBindViewHolder(ViewHolder vh, int position) {
int resourceId = resourceIds.get(position)
Glide.with(fragment)
.load(resourceId)
.into(new CustomViewTarget(vh.imageView));
尺寸
默认情况下,Glide 使用由 Targets 提供的 getSize() 大小作为请求的目标大小。这样做可以让 Glide 选择适当的 url,downsample,crop 和转换适当的图像,以尽量减少内存使用,并确保负载尽可能快。
最简单的实现方式是在 getSize() 方法中立即调用回调函数:
@Override
public void getSize(SizeReadyCallback cb) {
cb.onSizeReady(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
}
您还可以将尺寸传递给您的 Target 的构造函数,并将这些尺寸提供给回调:
public class CustomTarget<T> implements Target<T> {
private final int width;
private final int height;
public CustomTarget(int width, int height) {
this.width = width;
this.height = height;
}
...
@Override
public void getSize(SizeReadyCallback cb) {
cb.onSizeReady(width, height);
}
}
查看目标
ViewTarget 实现了 getSize() 方法,通过检查 View 的属性或者使用 onPreDrawListener 在渲染之前立即测量视图来实现。我们采用下面的逻辑:
- 如果任一视图的尺寸设置的值>0,则使用这些尺寸。
- 如果任一视图的尺寸设置成 WRAP_CONTENT,则使用屏幕的宽度或高度。
- 如果至少有一个视图的尺寸的值<=0 而不是 WRAP_CONTENT,则添加一个 OnPreDrawListener 来监听布局。
WRAP_CONTENT
请注意,Glide 不能很好的处理 WRAP_CONTENT,这是因为对于我们来说很难清楚用户的意图,特别是要求转换时。
我们可以看作 WRAP_CONTENT 是用户请求原始的未修改的图像,但是这样做在我们加载大图像时有内存溢出的风险。另外,特别是视图不会脱离屏幕,因此 Android 框架可能会最终缩小任何加载成功的全分辨率图像。
使用屏幕尺寸,我们至少可以对超大图像进行降低采样,而不会完全忽略用户的请求。
应用视图大小
一般来说,当在其加载的视图上设置显示 dp 大小时,Glide 提供了最快的和最可预测的结果。然而,当不可能这样时,Glide 还为布局权重,MATCH_PARENT 和其他相对尺寸提供了强大的支持 OnPreDrawListeners。最后,如果这些都没有设置,Glide 应该为 WRAP_CONTENT 提供了合理的行为。
备选方案
如果在任何情况下,Glide 似乎都会使 View 大小错误,您可以随时通过扩展 ViewTarget 和实现自己的逻辑来手动覆盖大小,或者通过使用 RequestOptions 中的 override() 方法。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论