Picasso源码阅读笔记二

412 阅读9分钟
Request

Request是图片请求,声明所请求的Bitmap的信息,比如Uri,资源id,目标宽高等等。Request采用Builder模式来创建,定义了内部类Request.Builder。

public final class Request {
  // Request的id,由AtomicInteger生成。
  int id;
  // 该请求第一次被提交的时间
  long started;
  // 网络策略
  int networkPolicy;

  // 图片的Uri
  public final Uri uri;
  // 图片的资源id,Uri和资源id两者只能选其一。
  public final int resourceId;
  // 替代Uri或资源id作为缓存时的key,该值相同则被认为是相同的Request。
  public final String stableKey;
  // 自定义的Transformation
  public final List<Transformation> transformations;
  // 给Bitmap设定的宽度
  public final int targetWidth;
  // 给Bitmap设定的高度
  public final int targetHeight;
  // scaleType是否为centerCrop
  public final boolean centerCrop;
  // scaleType是否为centerInside,centerInside和centerCrop只有一个为true。
  public final boolean centerInside;
  // 是否只是缩小图片
  public final boolean onlyScaleDown;
  // 旋转角度
  public final float rotationDegrees;
  // 旋转轴的X坐标
  public final float rotationPivotX;
  // 旋转轴的Y坐标
  public final float rotationPivotY;
  // 是否有旋转轴
  public final boolean hasRotationPivot;
  // Bitmap的Config
  public final Bitmap.Config config;
  // 优先级
  public final Priority priority;

}
Target

Target是图片加载的监听器。因为框架内部存储的原因,必须正确实现equals和hashCode方法。 当在Adapter中使用时,Target的实例会被比较进而判断是否正在回收View。为了保证ListView等的View回收机制能够正常运行,使用Adapter时推荐自定义View实现该接口。

public interface Target {
  // Bitmap成功加载时被回调,此处不能回收Bitmap。
  void onBitmapLoaded(Bitmap bitmap, LoadedFrom from);

  // Bitmap加载失败时被回调。
  void onBitmapFailed(Drawable errorDrawable);

  // Request被提交前被回调。
  void onPrepareLoad(Drawable placeHolderDrawable);
}
Action

Action是一个抽象类,有两个抽象方法。

abstract class Action<T> {
  // 定义了弱引用来保持ImageView,RemoteViews等,避免内存泄漏
  static class RequestWeakReference<M> extends WeakReference<M> {
    final Action action;

    public RequestWeakReference(Action action, M referent, ReferenceQueue<? super M> q) {
      super(referent, q);
      this.action = action;
    }
  }

  // 保持了对Request的引用
  final Request request;
  // 保持了对Target/ImageView/RemoteViews的弱引用。
  final WeakReference<T> target;
  
  // 成功获取Bitmap时被回调
  abstract void complete(Bitmap result, Picasso.LoadedFrom from);
  // Bitmap获取失败时被回调
  abstract void error();
}

Action的实现类有GetAction、FetchAction、ImageViewAction、RemoteViewsAction、NotificationAction和TargetAction。

RequestCreator

调用Picasso的load(Uri)或者load(String)方法可以获取RequestCreator对象。 RequestCreator提供了一系列的方法比如placeholder/error/tag等来设置Request.Builder,然后通过createRequest方法创建Request。 RequestCreator还提供一系列的方法来创建Action。

private Request createRequest(long started) {
  int id = nextId.getAndIncrement();

  // 通过Request.Buidler创建Requst,并设置id和started。
  Request request = data.build();
  request.id = id;
  request.started = started;

  boolean loggingEnabled = picasso.loggingEnabled;
  if (loggingEnabled) {
    log(OWNER_MAIN, VERB_CREATED, request.plainId(), request.toString());
  }

  // 如果Picasso设置了RequestTransformer,则对Request做转化。
  Request transformed = picasso.transformRequest(request);
  if (transformed != request) {
    // 如果Request被转化了,则给新Request并设置id和started。
    transformed.id = id;
    transformed.started = started;

    if (loggingEnabled) {
      log(OWNER_MAIN, VERB_CHANGED, transformed.logId(), "into " + transformed);
    }
  }

  return transformed;
}
GetAction
// 同步获取Bitmap,不能在主线程中调用该方法。
// 获取的Bitmap不会被缓存在内存中,因为Cache的实现不能保证是同步的。
public Bitmap get() throws IOException {
  long started = System.nanoTime();
  // 确保不是在主线程
  checkNotMain();

  if (deferred) {
    throw new IllegalStateException("Fit cannot be used with get.");
  }
  // 如果Uri或者资源id不存在,返回空。
  if (!data.hasImage()) {
    return null;
  }

  // 创建Request
  Request finalData = createRequest(started);
  String key = createKey(finalData, new StringBuilder());
  // 创建GetAction,forRequest创建出BitmapHunter,调用其hunt方法,同步获取Bitmap。
  Action action = new GetAction(picasso, finalData, memoryPolicy, networkPolicy, tag, key);
  return forRequest(picasso, picasso.dispatcher, picasso.cache, picasso.stats, action).hunt();
}

// 因为GetAction是同步获取Bitmap,所以它的泛型是Void,抽象方法的实现都是为空。
class GetAction extends Action<Void> {
  GetAction(Picasso picasso, Request data, int memoryPolicy, int networkPolicy, Object tag,
      String key) {
    super(picasso, null, data, memoryPolicy, networkPolicy, 0, null, key, tag, false);
  }

  @Override void complete(Bitmap result, Picasso.LoadedFrom from) {
  }

  @Override public void error() {
  }
}
FetchAction
// 异步获取Bitmap,然后回调Callback方法。 该方法可以用来预先给内存缓存添加图片。
// callback是强引用,在获取到Bitmap前,Activity和Fragment不能被垃圾回收。
public void fetch(Callback callback) {
  long started = System.nanoTime();

  if (deferred) {
    throw new IllegalStateException("Fit cannot be used with fetch.");
  }
  if (data.hasImage()) {
    // Request的priority默认是LOW。
    if (!data.hasPriority()) {
      data.priority(Priority.LOW);
    }
    //创建Request
    Request request = createRequest(started);
    String key = createKey(request, new StringBuilder());
    // 根据Request得出的key查找内存缓存
    Bitmap bitmap = picasso.quickMemoryCacheCheck(key);
    // 如果内存不为空则回调Callback方法。
    if (bitmap != null) {
      if (picasso.loggingEnabled) {
        log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
      }
        if (callback != null) {
        callback.onSuccess();
      }
    } else {
     // 如果内存没有,则创建FetchAction,提交到线程池执行。
      Action action =
          new FetchAction(picasso, request, memoryPolicy, networkPolicy, tag, key, callback);
      picasso.submit(action);
    }
  }
}

// 简单的回调方法。
public interface Callback {
  void onSuccess();

  void onError();

  public static class EmptyCallback implements Callback {

    @Override public void onSuccess() {
    }

    @Override public void onError() {
    }
  }
}

// FetchAction在抽象方法中回调Callback方法。
// FetchAction的泛型是Object。
class FetchAction extends Action<Object> {

  private final Object target;
  private Callback callback;

  FetchAction(Picasso picasso, Request data, int memoryPolicy, int networkPolicy, Object tag,
      String key, Callback callback) {
    // 因为target是普通的Object,而不是ImageView等会涉及Activity的内存回收,
    // 此处的target不像父类那样保存成弱引用。
    // 父类构造器的target为null。
    super(picasso, null, data, memoryPolicy, networkPolicy, 0, null, key, tag, false);
    // 把target保存到成员变量target。
    this.target = new Object();
    this.callback = callback;
  }

  @Override void complete(Bitmap result, Picasso.LoadedFrom from) {
    if (callback != null) {
      callback.onSuccess();
    }
  }

  @Override void error() {
    if (callback != null) {
      callback.onError();
    }
  }

  @Override void cancel() {
    super.cancel();
    // callback置为空,释放内存,以便系统回收Activity和Fragment。
    callback = null;
  }

  @Override Object getTarget() {
    // 返回target。
    return target;
  }
}
ImageViewAction
// 异步请求Bitmap,加载到ImageView中,并回调Callback方法。
// ImageView被保存为弱引用,但是Callback是强引用,会阻止Activity和Fragment被回收,记得调用cancel方法取消请求。
public void into(ImageView target, Callback callback) {
  long started = System.nanoTime();
  // 在主线程中调用该方法。
  checkMain();

  if (target == null) {
    throw new IllegalArgumentException("Target must not be null.");
  }

  // 如果Uri或者资源id不存在,则取消ImageView的其他请求,显示预加载图片。
  if (!data.hasImage()) {
    picasso.cancelRequest(target);
    if (setPlaceholder) {
      setPlaceholder(target, getPlaceholderDrawable());
    }
    return;
  }
  // 如果Bitmap要按照ImageView的宽高来显示
  if (deferred) {
    if (data.hasSize()) {
      throw new IllegalStateException("Fit cannot be used with resize.");
    }
    int width = target.getWidth();
    int height = target.getHeight();
    // 如果ImageView的宽高都不知道,则交给Picasso的defer延迟处理。
    if (width == 0 || height == 0) {
      if (setPlaceholder) {
        setPlaceholder(target, getPlaceholderDrawable());
      }
      picasso.defer(target, new DeferredRequestCreator(this, target, callback));
    return;
    }
    // 否则把Request的宽高设为ImageView的宽高。
    data.resize(width, height);
  }
  // 创建Request
  Request request = createRequest(started);
  String requestKey = createKey(request);
  // 如果允许从内存缓存中读取
  if (shouldReadFromMemoryCache(memoryPolicy)) {
     Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
    if (bitmap != null) {
      // 内存缓存读取成功,取消ImageView的其他请求,显示Bitmap,回调Callback方法。
      picasso.cancelRequest(target);
      setBitmap(target, picasso.context, bitmap, MEMORY, noFade, picasso.indicatorsEnabled);
      if (picasso.loggingEnabled) {
        log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
      }
      if (callback != null) {
        callback.onSuccess();
      }
      return;
    }
  }

  // 显示预加载图片
  if (setPlaceholder) {
    setPlaceholder(target, getPlaceholderDrawable());
  }
  // 创建ImageViewAction,提交到线程池中执行。
  Action action =
      new ImageViewAction(picasso, target, request, memoryPolicy, networkPolicy, errorResId,
          errorDrawable, requestKey, tag, callback, noFade);

  picasso.enqueueAndSubmit(action);
}

// 把获取吃的Bitmap转化成PicassoDrawable,加载到ImageView中,并回调Callback方法。
class ImageViewAction extends Action<ImageView> {

  Callback callback;

  ImageViewAction(Picasso picasso, ImageView imageView, Request data, int memoryPolicy,
      int networkPolicy, int errorResId, Drawable errorDrawable, String key, Object tag,
      Callback callback, boolean noFade) {
    super(picasso, imageView, data, memoryPolicy, networkPolicy, errorResId, errorDrawable, key,
        tag, noFade);
    this.callback = callback;
  }

  @Override public void complete(Bitmap result, Picasso.LoadedFrom from) {
    if (result == null) {
      throw new AssertionError(
          String.format("Attempted to complete action with no result!\n%s", this));
    }

    ImageView target = this.target.get();
    if (target == null) {
      return;
    }

    Context context = picasso.context;
    boolean indicatorsEnabled = picasso.indicatorsEnabled;
    PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);

    if (callback != null) {
      callback.onSuccess();
    }
  }

  @Override public void error() {
    ImageView target = this.target.get();
    if (target == null) {
      return;
    }
    if (errorResId != 0) {
      target.setImageResource(errorResId);
    } else if (errorDrawable != null) {
      target.setImageDrawable(errorDrawable);
    }

    if (callback != null) {
      callback.onError();
    }
  }

  @Override void cancel() {
    super.cancel();
    if (callback != null) {
      callback = null;
    }
  }
}
TargetAction
// 异步请求Bitmap,然后回调Target的方法。
// 当使用实现Target接口的自定义View或者Adapter的ViewHolder,使用该方法。
public void into(Target target) {
  long started = System.nanoTime();
  // 在主线程中调用该方法。
  checkMain();

  if (target == null) {
    throw new IllegalArgumentException("Target must not be null.");
  }
  if (deferred) {
    throw new IllegalStateException("Fit cannot be used with a Target.");
  }

  // 如果Uri或者资源id为空时,取消Target已有的请求,然后显示预加载的图片。
  if (!data.hasImage()) {
    picasso.cancelRequest(target);
    target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
    return;
  }

  // 创建Request。
  Request request = createRequest(started);
  String requestKey = createKey(request);

  // 如果运行读取内存缓存。
  if (shouldReadFromMemoryCache(memoryPolicy)) {
    Bitmap bitmap = picasso.quickMemoryCacheCheck(requestKey);
    if (bitmap != null) {
      // 内存缓存读取成功,取消Target上已有的请求,回调Target方法。
      picasso.cancelRequest(target);
      target.onBitmapLoaded(bitmap, MEMORY);
      return;
    }
  }

  // 显示预加载的图片
  target.onPrepareLoad(setPlaceholder ? getPlaceholderDrawable() : null);
  // 创建TargetAction,提交到线程池中执行。
  Action action =
      new TargetAction(picasso, target, request, memoryPolicy, networkPolicy, errorDrawable,
          requestKey, tag, errorResId);
  picasso.enqueueAndSubmit(action);
}

// TargetAction的泛型是Target
final class TargetAction extends Action<Target> {

  TargetAction(Picasso picasso, Target target, Request data, int memoryPolicy, int networkPolicy,
      Drawable errorDrawable, String key, Object tag, int errorResId) {
    super(picasso, target, data, memoryPolicy, networkPolicy, errorResId, errorDrawable, key, tag,
        false);
  }

  @Override void complete(Bitmap result, Picasso.LoadedFrom from) {
    if (result == null) {
      throw new AssertionError(
          String.format("Attempted to complete action with no result!\n%s", this));
    }
    Target target = getTarget();
    if (target != null) {
      target.onBitmapLoaded(result, from);
      if (result.isRecycled()) {
        throw new IllegalStateException("Target callback must not recycle bitmap!");
      }
    }
  }

  @Override void error() {
    Target target = getTarget();
    if (target != null) {
      if (errorResId != 0) {
        target.onBitmapFailed(picasso.context.getResources().getDrawable(errorResId));
      } else {
        target.onBitmapFailed(errorDrawable);
      }
    }
  }
}

RemoteViewsAction
// 异步加载Bitmamp到Notification中
public void into(RemoteViews remoteViews, int viewId, int notificationId,
    Notification notification) {
  long started = System.nanoTime();

  if (remoteViews == null) {
    throw new IllegalArgumentException("RemoteViews must not be null.");
  }
  if (notification == null) {
    throw new IllegalArgumentException("Notification must not be null.");
  }
  if (deferred) {
    throw new IllegalStateException("Fit cannot be used with RemoteViews.");
  }
  if (placeholderDrawable != null || placeholderResId != 0 || errorDrawable != null) {
    throw new IllegalArgumentException(
        "Cannot use placeholder or error drawables with remote views.");
  }
  // 创建Request
  Request request = createRequest(started);
  String key = createKey(request, new StringBuilder()); // Non-main thread needs own builder.
  // 创建RemoteViewsAction
  RemoteViewsAction action =
      new NotificationAction(picasso, request, remoteViews, viewId, notificationId, notification,
          memoryPolicy, networkPolicy, key, tag, errorResId);

  performRemoteViewInto(action);
}

// 异步加载Bitmamp到Widget中
public void into(RemoteViews remoteViews, int viewId, int[] appWidgetIds) {
  long started = System.nanoTime();

  if (remoteViews == null) {
    throw new IllegalArgumentException("remoteViews must not be null.");
  }
  if (appWidgetIds == null) {
    throw new IllegalArgumentException("appWidgetIds must not be null.");
  }
  if (deferred) {
    throw new IllegalStateException("Fit cannot be used with remote views.");
  }
  if (placeholderDrawable != null || placeholderResId != 0 || errorDrawable != null) {
    throw new IllegalArgumentException(
        "Cannot use placeholder or error drawables with remote views.");
  }
  // 创建Request
  Request request = createRequest(started);
  String key = createKey(request, new StringBuilder()); // Non-main thread needs own builder.
  // 创建AppWidgetAction
  RemoteViewsAction action =
      new AppWidgetAction(picasso, request, remoteViews, viewId, appWidgetIds, memoryPolicy,
          networkPolicy, key, tag, errorResId);

  performRemoteViewInto(action);
}


private void performRemoteViewInto(RemoteViewsAction action) {
  // 如果允许读取内存缓存
  if (shouldReadFromMemoryCache(memoryPolicy)) {
    Bitmap bitmap = picasso.quickMemoryCacheCheck(action.getKey());
    // 如果内存缓存读取成功,则调用RemoteViewsAction的complete方法。
    if (bitmap != null) {
      action.complete(bitmap, MEMORY);
      return;
    }
  }

  if (placeholderResId != 0) {
    action.setImageResource(placeholderResId);
  }
  // 否则交给线程池处理
  picasso.enqueueAndSubmit(action);
}

// RemoteViewsAction的泛型是RemoteViewsTarget
abstract class RemoteViewsAction extends Action<RemoteViewsAction.RemoteViewsTarget> {
  final RemoteViews remoteViews;
  final int viewId;

  private RemoteViewsTarget target;

  RemoteViewsAction(Picasso picasso, Request data, RemoteViews remoteViews, int viewId,
      int errorResId, int memoryPolicy, int networkPolicy, Object tag, String key) {
    super(picasso, null, data, memoryPolicy, networkPolicy, errorResId, null, key, tag, false);
    this.remoteViews = remoteViews;
    this.viewId = viewId;
  }

  @Override void complete(Bitmap result, Picasso.LoadedFrom from) {
    remoteViews.setImageViewBitmap(viewId, result);
    update();
  }

  @Override public void error() {
    if (errorResId != 0) {
      setImageResource(errorResId);
    }
  }

  @Override RemoteViewsTarget getTarget() {
    if (target == null) {
      target = new RemoteViewsTarget(remoteViews, viewId);
    }
    return target;
  }

  void setImageResource(int resId) {
    remoteViews.setImageViewResource(viewId, resId);
    update();
  }

  abstract void update();

  static class RemoteViewsTarget {
    final RemoteViews remoteViews;
    final int viewId;

    RemoteViewsTarget(RemoteViews remoteViews, int viewId) {
      this.remoteViews = remoteViews;
      this.viewId = viewId;
    }

    @Override public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;
      RemoteViewsTarget remoteViewsTarget = (RemoteViewsTarget) o;
      return viewId == remoteViewsTarget.viewId && remoteViews.equals(
          remoteViewsTarget.remoteViews);
    }

    @Override public int hashCode() {
      return 31 * remoteViews.hashCode() + viewId;
    }
  }

  static class AppWidgetAction extends RemoteViewsAction {
    private final int[] appWidgetIds;

    AppWidgetAction(Picasso picasso, Request data, RemoteViews remoteViews, int viewId,
        int[] appWidgetIds, int memoryPolicy, int networkPolicy, String key, Object tag,
        int errorResId) {
      super(picasso, data, remoteViews, viewId, errorResId, memoryPolicy, networkPolicy, tag, key);
      this.appWidgetIds = appWidgetIds;
    }

    @Override void update() {
      AppWidgetManager manager = AppWidgetManager.getInstance(picasso.context);
      manager.updateAppWidget(appWidgetIds, remoteViews);
    }
  }

  static class NotificationAction extends RemoteViewsAction {
    private final int notificationId;
    private final Notification notification;

    NotificationAction(Picasso picasso, Request data, RemoteViews remoteViews, int viewId,
        int notificationId, Notification notification, int memoryPolicy, int networkPolicy,
        String key, Object tag, int errorResId) {
      super(picasso, data, remoteViews, viewId, errorResId, memoryPolicy, networkPolicy, tag, key);
      this.notificationId = notificationId;
      this.notification = notification;
    }

    @Override void update() {
      NotificationManager manager = getService(picasso.context, NOTIFICATION_SERVICE);
      manager.notify(notificationId, notification);
    }
  }
}
DeferredRequestCreator

如果想把Bitmap加载到ImageView中,且Bitmap按照ImageView的宽高来显示,需要调用RequestCreator的fit()方法。该方法把RequestCreator封装成DeferredRequestCreator。DeferredRequestCreator会监听ImageView的绘制,获取到其具体宽高后再通过RequestCreator请求图片。

// DeferredRequestedCreator实现了ViewTreeObserver.OnPreDrawListener接口,来获取ImageView的宽高。
class DeferredRequestCreator implements ViewTreeObserver.OnPreDrawListener {

  final RequestCreator creator;
  final WeakReference<ImageView> target;
  Callback callback;

  DeferredRequestCreator(RequestCreator creator, ImageView target, Callback callback) {
    this.creator = creator;
    this.target = new WeakReference<ImageView>(target);
    this.callback = callback;
    // 注册监听器
    target.getViewTreeObserver().addOnPreDrawListener(this);
  }

  @Override public boolean onPreDraw() {
    ImageView target = this.target.get();
    if (target == null) {
      return true;
    }
    ViewTreeObserver vto = target.getViewTreeObserver();
    if (!vto.isAlive()) {
      return true;
    }

    int width = target.getWidth();
    int height = target.getHeight();

    if (width <= 0 || height <= 0) {
      return true;
    }
    // 获取其宽高后移除监听器
    vto.removeOnPreDrawListener(this);
    // 把Reqeust的宽高设置成ImageView的宽高,然后调用RequestCreator的into方法请求Bitmap
    this.creator.unfit().resize(width, height).into(target, callback);
    return true;
  }

  // 取消请求时,Callback置为空,同时移除监听器
  void cancel() {
    callback = null;
    ImageView target = this.target.get();
    if (target == null) {
      return;
    }
    ViewTreeObserver vto = target.getViewTreeObserver();
    if (!vto.isAlive()) {
      return;
    }
    vto.removeOnPreDrawListener(this);
  }
}