手记

Glide v4 目标

关于Target

在Glide中,Target 是介于请求和请求者之间的中介者的角色。Target 负责展示占位符,加载资源,并为每个请求决定合适的尺寸。被使用得最频繁的是 ImageViewTargets ,它用于在 ImageView 上展示占位符、Drawable 和 Bitmap 。用户还可以实现自己的 Target ,或者从任何可用的基类派生子类。

指定目标

into(Target) 方法不仅仅用于启动每个请求,它同时也指定了接收请求结果的 Target 。Glide 提供了一个辅助方法 into(ImageView) ,它接受一个 ImageView参数并为请求的资源类型指定了合适的 Target 。

为了让使用自定义的 Target 更方便,into() 方法返回了提供给它的参数:

Target<Bitmap> target = Glide.with(fragment)
        .asBitmap()
        .load(url)
        .into(imageView);...// Some time later:Glide.with(fragment).clear(target);

目标和自动取消

Target可以(并且通常应当)被复用于会在同一个地方展示的一连串加载过程。 复用 Target 允许 Glide 在新的加载开始时自动取消或复用旧的加载过程的资源。 Target 复用失败可能导致旧的请求资源替换掉稍新请求的资源。

定制目标

复用自定义 Target 的一个简单方案,保持它们的实例引用就行了:

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() 方法来查找 Target ,或取消 Target 上的请求。这意味着所有的自定义 Target 都必须实现这些方法。最简单的办法莫过于直接继承 BaseTarget .

View目标

一些自定义的Target能为 getRequest() 和 setRequest() 方法提供更为智能的实现,以避免复用 Target 的一些严格要求。例如 ViewTarget,它利用了Android 框架的 getTag() 和 setTag() 方法来完成这些工作。

@Overridepublic Request getRequest() {
    return (Request) view.getTag();}@Overridepublic void setRequest(Request request) {
    view.setTag(request);}

因为 tag 是 View 的属性,所以属于新一次请求的 ViewTarget 可以在很容易地从之前的 ViewTarget 中找出并取消/复用之前的请求。

这样做的一个好处是,当你使用 into(ImageView) 向view中加载图片时,或你从 ViewTarget 派生出了新的 Target 时,你可以为每次加载都传入一个新的 Target:

@Overridepublic void onBindViewHolder(ViewHolder vh, int position) {
  int resourceId = resourceIds.get(position)
  Glide.with(fragment)
      .load(resourceId)
      .into(new CustomViewTarget(vh.imageView));

尺寸测量

默认情况下,Glide 使用 Target 通过 getSize() 方法提供的尺寸作为请求的目标尺寸。这种设计允许 Glide 可以选取合适的 url ,降低采样率,剪裁和转换图像,从而最小化内存的使用,并确保加载尽可能快。

最简单的实现getSize()的方法可能是直接调用库提供的回调:

定制目标

@Overridepublic 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);
  }}

View目标

ViewTarget 通过检查 View 的属性和/或使用一个 OnPreDrawListener 在 View 绘制之前直接测量尺寸来实现 getSize() 方法。我们使用以下逻辑:

  1. 如果 View 的的宽或高被设置为 > 0,则使用这个尺寸

  2. 如果 View 的宽或高被设置为 WRAP_CONTENT ,则使用屏幕的宽或高

  3. 如果仍然至少有一个维度 <= 0 并且不是 WRAP_CONTENT ,添加一个 OnPreDrawListener 监听布局。

WRAP_CONTENT

请注意,Glide 可能对 WRAP_CONTENT 处理不是特别好。这是因为我们很难知道用户的实际意图,尤其是还请求了变换(Transformations)的时候。

我们可以将 WRAP_CONTENT 视为用户请求原始的未修改的图像,但这么做会有在加载超大图像时导致 OutOfMemoryException 的风险。另外,尤其是因为View通常不会超出屏幕,Android Framework 最后可能会将我们设法成功加载的任意高分辨率图像给缩小(downscaling)。

使用屏幕尺寸,至少允许我们缩小超大的图片,而又不完全忽略用户的原始请求意图。

尺寸与性能

一般来说,在加载图片的 View 被设置了显式的dp尺寸的情况下,Glide 提供了最快、最可预测的结果。在不可能获得明确的 dp 尺寸时,Glide 也通过使用 OnPreDrawListeners 为 layout weightMATCH_PARENT 以及其他相对尺寸提供了相当鲁棒的支持。如果这些都不奏效,Glide 也为 WRAP_CONTENT 提供了应该较为合理的行为。

其他情况

在任何情况下,如果 Glide 看起来获取了错误的 View 尺寸,你都可以手动覆盖来纠正它。你可以选择扩展 ViewTarget 实现你自己的逻辑,或者使用 RequestOption 里的方法。

原文链接:http://www.apkbus.com/blog-873055-75806.html

0人推荐
随时随地看视频
慕课网APP