Picasso源码阅读笔记一

214 阅读5分钟

该系列文章是阅读Picasso 2.5.2源码的笔记。

Picasso.Buidler

Picasso的构造函数如下。

Picasso(Context context, Dispatcher dispatcher, Cache cache, Listener listener,
    RequestTransformer requestTransformer, List<RequestHandler> extraRequestHandlers, Stats stats,
    Bitmap.Config defaultBitmapConfig, boolean indicatorsEnabled, boolean loggingEnabled) {
  this.context = context;
  this.dispatcher = dispatcher;
  this.cache = cache; //内存缓存
  this.listener = listener; //图片加载失败监听器
  this.requestTransformer = requestTransformer; //Request转换器
  this.defaultBitmapConfig = defaultBitmapConfig; //Bitmap.Config对象

  int builtInHandlers = 7; //7个内置的RequestHandler
  int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
  List<RequestHandler> allRequestHandlers =
      new ArrayList<RequestHandler>(builtInHandlers + extraCount);

  // ResourceRequestHandler放在第一位,让后面的RequestHandler只需检查request.uri,而不用处理request.resourceId != 0的情况。
  allRequestHandlers.add(new ResourceRequestHandler(context));
  // 自定义的RequestHandlers从第二个开始
  if (extraRequestHandlers != null) {
    allRequestHandlers.addAll(extraRequestHandlers);
  }
  // 按以下顺序添加内置的RequestHandler
  allRequestHandlers.add(new ContactsPhotoRequestHandler(context));
  allRequestHandlers.add(new MediaStoreRequestHandler(context));
  allRequestHandlers.add(new ContentStreamRequestHandler(context));
  allRequestHandlers.add(new AssetRequestHandler(context));
  allRequestHandlers.add(new FileRequestHandler(context));
  allRequestHandlers.add(new NetworkRequestHandler(dispatcher.downloader, stats));
  requestHandlers = Collections.unmodifiableList(allRequestHandlers);

  this.stats = stats; //内存状态对象
   //注意这里因为考虑到内存回收使用的是WeakHashMap。
   //因为两个Map只在主线程处理,所以不用考虑线程安全问题。
   //Picasso和Dispatcher虽然都保存了Target和Action的Map
   //但是Picasso保存的是所有的Action,只有完成和取消的才会被移除。
   // Dispatcher保存的是暂停和失败的Action。
  this.targetToAction = new WeakHashMap<Object, Action>(); 
  this.targetToDeferredRequestCreator = new WeakHashMap<ImageView, DeferredRequestCreator>(); 
  this.indicatorsEnabled = indicatorsEnabled; //是否显示图片来源标记
  this.loggingEnabled = loggingEnabled; //是否打印日志
  this.referenceQueue = new ReferenceQueue<Object>(); //Action的Target的弱引用队列
  this.cleanupThread = new CleanupThread(referenceQueue, HANDLER); //开启回收线程
  this.cleanupThread.start();
}

public interface Listener {
  // 图片加载失败时,回调该方法。这适用于给服务器发送图片加载失败的情况。
  void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception);
}

可通过Picasso.Buidler的各种方法来配置Picasso,最后通过build()方法创建Picasso实例。

// 如果没给Picasso做任何的配置,则默认使用下面的配置。
public Picasso build() {
    Context context = this.context;

    if (downloader == null) {
      downloader = Utils.createDefaultDownloader(context);
    }
    if (cache == null) {
      cache = new LruCache(context);
    }
    if (service == null) {
      service = new PicassoExecutorService();
    }
    if (transformer == null) {
      transformer = RequestTransformer.IDENTITY;
    }

    Stats stats = new Stats(cache);

    Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, downloader, cache, stats);

    return new Picasso(context, dispatcher, cache, listener, transformer, requestHandlers, stats,
        defaultBitmapConfig, indicatorsEnabled, loggingEnabled);
  }
}
单例模式

通过with()方法获取全局单例的Picasso对象。这里的单例模式采用的是双重检查。

public static Picasso with(Context context) {
  if (singleton == null) {
    synchronized (Picasso.class) {
      if (singleton == null) {
        singleton = new Builder(context).build();
      }
    }
  }
  return singleton;
}

默认情况下是使用能满足大部分需求的默认配置,线程池的核心线程数是3,内存缓存是可用RAM的15%,在API 14以上是2%的磁盘存储,最大50M,最小5M,如果是使用了OkHttp,则使用OkHttp的磁盘缓存。

如果获取自定义配置的Picasso单例,先通过Picasso.Builder创建自定义配置的Picasso对象,接着调用setSingletonInstance()方法,把自定义Picasso对象设置为全局单例,然后在其他地方通过with()方法就可以得到自定义的Picasso单例。

停止接收请求

当不想再接收图片请求时,调用Picasso的shutdown方法。

public void shutdown() {
  if (this == singleton) {
    throw new UnsupportedOperationException("Default singleton instance cannot be shutdown.");
  }
  if (shutdown) {
    return;
  }
  cache.clear(); //清空内存缓存
  cleanupThread.shutdown(); //停止回收Target的线程
  stats.shutdown(); //停止记录内存状态的线程
  dispatcher.shutdown(); //停止Dispatcher的现场
  // 移除ImageView的监听器
  for (DeferredRequestCreator deferredRequestCreator : targetToDeferredRequestCreator.values()) {
    deferredRequestCreator.cancel();
  }
  targetToDeferredRequestCreator.clear();
  shutdown = true;
}
HANDLER

Picasso有一个静态成员变量HANDLER,负责处理在主线程中处理其他线程发生过来的消息。

static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
  @Override public void handleMessage(Message msg) {
    switch (msg.what) {
      case HUNTER_BATCH_COMPLETE: {
        // Dispatcher发送的消息,BitmapHunter任务执行结束。
        for (int i = 0, n = batch.size(); i < n; i++) {
          BitmapHunter hunter = batch.get(i);
          hunter.picasso.complete(hunter);
        }
        break;
      }
      case REQUEST_GCED: {
        // CleanThread发送的消息,当有弱引用被回收时,取消请求。
        Action action = (Action) msg.obj;
        if (action.getPicasso().loggingEnabled) {
          log(OWNER_MAIN, VERB_CANCELED, action.request.logId(), "target got garbage collected");
        }
        action.picasso.cancelExistingRequest(action.getTarget());
        break;
      }
      case REQUEST_BATCH_RESUME:
        // Dispatcher发送的消息,恢复请求。
        for (int i = 0, n = batch.size(); i < n; i++) {
          Action action = batch.get(i);
          action.picasso.resumeAction(action);
        }
        break;
      default:
        throw new AssertionError("Unknown handler message received: " + msg.what);
    }
  }
};
Picasso的其他方法
// 当RequestCreator创建出Action后,调用该方法
void enqueueAndSubmit(Action action) {
  Object target = action.getTarget();
  if (target != null && targetToAction.get(target) != action) {
    // 如果target已有Action,则取消原来的请求
    cancelExistingRequest(target);
    // 保存新Action
    targetToAction.put(target, action);
  }
  submit(action);
}

// 把Action交给Dispatcher的Handler处理,最终是提交到线程池中执行。
void submit(Action action) {
  dispatcher.dispatchSubmit(action);
}
// 当BitmapHunter执行结束向Dispatcher发生Complete或者Error消息。
// Dispatcher不管BitmapHunter成功还是失败,最后都是向Picasso的HANDLER发生Complete消息。
// Picasso的HANDLER调用该方法,在该方法中根据结果回调Action的方法。
void complete(BitmapHunter hunter) {
  // 获取BitmapHunter的主Action和次Action。
  Action single = hunter.getAction();
  List<Action> joined = hunter.getActions();

  boolean hasMultiple = joined != null && !joined.isEmpty(); //是否有次Action
  boolean shouldDeliver = single != null || hasMultiple; //是否有Action需要处理

  // 如果没有Action需要处理则返回
  if (!shouldDeliver) {
    return;
  }

  Uri uri = hunter.getData().uri;
  Exception exception = hunter.getException();
  Bitmap result = hunter.getResult();
  LoadedFrom from = hunter.getLoadedFrom();

  // 如果存在主Action,则把结果传给主Action
  if (single != null) {
    deliverAction(result, from, single);
  }

  if (hasMultiple) {
    // 如果存在次Action,则结果依次传给次Action。
    for (int i = 0, n = joined.size(); i < n; i++) {
      Action join = joined.get(i);
      deliverAction(result, from, join);
    }
  }

  // 如果存在监听器且请求失败,则回调监听器方法。
  if (listener != null && exception != null) {
    listener.onImageLoadFailed(this, uri, exception);
  }
}

private void deliverAction(Bitmap result, LoadedFrom from, Action action) {
  // 如果Action已被取消,则返回。
  if (action.isCancelled()) {
    return;
  }
  // 如果Action不需要重试,则把它从Map中移除,否则保留。
  if (!action.willReplay()) {
    targetToAction.remove(action.getTarget());
  }
  if (result != null) {
    if (from == null) {
      throw new AssertionError("LoadedFrom cannot be null.");
    }
    // 请求成功,则回调Action的complete方法。
    action.complete(result, from);
    if (loggingEnabled) {
      log(OWNER_MAIN, VERB_COMPLETED, action.request.logId(), "from " + from);
    }
  } else {
    // 请求失败,则回调Action的error方法。
    action.error();
    if (loggingEnabled) {
      log(OWNER_MAIN, VERB_ERRORED, action.request.logId());
    }
  }
}
// 取消处理中的请求
private void cancelExistingRequest(Object target) {
  // 必须在主线程中调用该方法
  checkMain();
  // 从Map移除对应的请求。
  Action action = targetToAction.remove(target);
  if (action != null) {
    action.cancel(); //Action的cancel()方法只是改变标记位。
    dispatcher.dispatchCancel(action); //通过Dispatcher尝试取消BitmapHunter。
  }
  // 如果target是ImageView,且有对应的DeferredRequestCreator,则解除对应的监听器。
  if (target instanceof ImageView) {
    ImageView targetImageView = (ImageView) target;
    DeferredRequestCreator deferredRequestCreator =
        targetToDeferredRequestCreator.remove(targetImageView);
    if (deferredRequestCreator != null) {
      deferredRequestCreator.cancel();
    }
  }
}

// 取消带有标记tag的请求
public void cancelTag(Object tag) {
  // 必须在主线程中调用该方法。
  checkMain();
  // 获取所有的Action
  List<Action> actions = new ArrayList<Action>(targetToAction.values());
  // 迭代所有的Action,如果带有标记tag则通过cancelExistingRequest方法取消请求。
  for (int i = 0, n = actions.size(); i < n; i++) {
    Action action = actions.get(i);
    if (action.getTag().equals(tag)) {
      cancelExistingRequest(action.getTarget());
    }
  }
}
// 暂停带有标记tag的请求
public void pauseTag(Object tag) {
  // 通过Dispatcher尝试取消对应的请求,并把Action放入pausedActions中。
  dispatcher.dispatchPauseTag(tag); 
}

// 恢复带有标记tag的请求
public void resumeTag(Object tag) {
  // 通过Dispatcher尝试恢复对应的请求,并把Action放入pausedActions中。
  dispatcher.dispatchResumeTag(tag);
}
对应关系

Request和BitmapHunter是一对一

Request和Action是一对多

BitmapHunter和Action是一对多

Target和Action是一对一