该系列文章是阅读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是一对一