Android 源码解析: 图片加载库Picasso 4 任务调度 Dispatcher
Picasso是Picasso框架的入口,同时也负责初始化各种工作的子线程,工作的实例;RequestCreator则是对任务的描述;而BitmapHunter则是一个具体的工作的线程,接受Picasso中配置好的调度池的调度同时负责知道对应的ReqeustHandler去执行数据请求,并将结果解析为图片,还可以进行一些图片的处理(Transformation),在Picasso当中,任务调度用的类是Dispatcher。
任务调度用的类Dispatcher可以说是Picasso库中最为重要的类之一了,他连接这Picasso中各个类和各个线程。其本身又是消息调度核心类,很多重要的类都与他直接关联,看懂了Dispatcher,就看懂了Picasso的核心了。没事画了个类图,理理了类之间的具体关系;如下图下面看看具体是怎么实现任务调度的。
Dispatcher内有一个HandlerThread(DispatcherThread extends HandlerThread),所有的请求都会通过这个thread转换,也就是请求也是异步的,这样应该是为了Ui线程更加流畅,同时保证请求的顺序。其主要流程是:
首先是外部调用的是dispatchXXX()方法,然后通过handler将请求转换到对应的performXXX()方法。
最后,将通过action得到具体的BitmapHunder,然后交给ExecutorService执行。
例如生成Action以后就会调用dispather的dispatchSubmit()来请求执行等,
首先是一堆dispatchXXX()源码如下:
void dispatchSubmit(Action action) {
handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
}
void dispatchCancel(Action action) {
handler.sendMessage(handler.obtainMessage(REQUEST_CANCEL, action));
}
void dispatchPauseTag(Object tag) {
handler.sendMessage(handler.obtainMessage(TAG_PAUSE, tag));
}
void dispatchResumeTag(Object tag) {
handler.sendMessage(handler.obtainMessage(TAG_RESUME, tag));
}
void dispatchComplete(BitmapHunter hunter) {
handler.sendMessage(handler.obtainMessage(HUNTER_COMPLETE, hunter));
}
void dispatchRetry(BitmapHunter hunter) {
handler.sendMessageDelayed(handler.obtainMessage(HUNTER_RETRY, hunter),
RETRY_DELAY);
}
void dispatchFailed(BitmapHunter hunter) {
handler.sendMessage(handler.obtainMessage(HUNTER_DECODE_FAILED, hunter));
}
void dispatchNetworkStateChange(NetworkInfo info) {
handler.sendMessage(handler.obtainMessage(NETWORK_STATE_CHANGE, info));
}
void dispatchAirplaneModeChange(boolean airplaneMode) {
handler.sendMessage(handler.obtainMessage(AIRPLANE_MODE_CHANGE,
airplaneMode ? AIRPLANE_MODE_ON : AIRPLANE_MODE_OFF, 0));
}
接着就是一堆回调xxx
private static class DispatcherHandler extends Handler {
private final Dispatcher dispatcher;
public DispatcherHandler(Looper looper, Dispatcher dispatcher) {
super(looper);
this.dispatcher = dispatcher;
}
@Override
public void handleMessage(final Message msg) {
switch (msg.what) {
case REQUEST_SUBMIT: {
Action action = (Action) msg.obj;
dispatcher.performSubmit(action);
break;
}
case REQUEST_CANCEL: {
Action action = (Action) msg.obj;
dispatcher.performCancel(action);
break;
}
case TAG_PAUSE: {
Object tag = msg.obj;
dispatcher.performPauseTag(tag);
break;
}
case TAG_RESUME: {
Object tag = msg.obj;
dispatcher.performResumeTag(tag);
break;
}
case HUNTER_COMPLETE: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performComplete(hunter);
break;
}
case HUNTER_RETRY: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performRetry(hunter);
break;
}
case HUNTER_DECODE_FAILED: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performError(hunter, false);
break;
}
case HUNTER_DELAY_NEXT_BATCH: {
dispatcher.performBatchComplete();
break;
}
case NETWORK_STATE_CHANGE: {
NetworkInfo info = (NetworkInfo) msg.obj;
dispatcher.performNetworkStateChange(info);
break;
}
case AIRPLANE_MODE_CHANGE: {
dispatcher.performAirplaneModeChange(msg.arg1 == AIRPLANE_MODE_ON);
break;
}
default:
Picasso.HANDLER.post(new Runnable() {
@Override
public void run() {
throw new AssertionError("Unknown handler message received: "
+ msg.what);
}
});
}
}
}
然后看看一堆performxxx(...) void performSubmit(Action action, boolean dismissFailed) {
if (pausedTags.contains(action.getTag())) {
pausedActions.put(action.getTarget(), action);
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),
"because tag '" + action.getTag() + "' is paused");
}
return;
}
BitmapHunter hunter = hunterMap.get(action.getKey());
if (hunter != null) {
hunter.attach(action);
return;
}
if (service.isShutdown()) {
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_IGNORED, action.request.logId(),
"because shut down");
}
return;
}
hunter = forRequest(action.getPicasso(), this, cache, stats, action);
hunter.future = service.submit(hunter);
hunterMap.put(action.getKey(), hunter);
if (dismissFailed) {
failedActions.remove(action.getTarget());
}
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_ENQUEUED, action.request.logId());
}
}
void performCancel(Action action) {
String key = action.getKey();
BitmapHunter hunter = hunterMap.get(key);
if (hunter != null) {
hunter.detach(action);
if (hunter.cancel()) {
hunterMap.remove(key);
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_CANCELED, action.getRequest().logId());
}
}
}
if (pausedTags.contains(action.getTag())) {
pausedActions.remove(action.getTarget());
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_CANCELED, action.getRequest().logId(),
"because paused request got canceled");
}
}
Action remove = failedActions.remove(action.getTarget());
if (remove != null && remove.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_CANCELED, remove.getRequest().logId(),
"from replaying");
}
}
void performPauseTag(Object tag) {
// Trying to pause a tag that is already paused.
if (!pausedTags.add(tag)) {
return;
}
// Go through all active hunters and detach/pause the requests
// that have the paused tag.
for (Iterator<BitmapHunter> it = hunterMap.values().iterator(); it
.hasNext();) {
BitmapHunter hunter = it.next();
boolean loggingEnabled = hunter.getPicasso().loggingEnabled;
Action single = hunter.getAction();
List<Action> joined = hunter.getActions();
boolean hasMultiple = joined != null && !joined.isEmpty();
// Hunter has no requests, bail early.
if (single == null && !hasMultiple) {
continue;
}
if (single != null && single.getTag().equals(tag)) {
hunter.detach(single);
pausedActions.put(single.getTarget(), single);
if (loggingEnabled) {
log(OWNER_DISPATCHER, VERB_PAUSED, single.request.logId(),
"because tag '" + tag + "' was paused");
}
}
if (hasMultiple) {
for (int i = joined.size() - 1; i >= 0; i--) {
Action action = joined.get(i);
if (!action.getTag().equals(tag)) {
continue;
}
hunter.detach(action);
pausedActions.put(action.getTarget(), action);
if (loggingEnabled) {
log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(),
"because tag '" + tag + "' was paused");
}
}
}
// Check if the hunter can be cancelled in case all its requests
// had the tag being paused here.
if (hunter.cancel()) {
it.remove();
if (loggingEnabled) {
log(OWNER_DISPATCHER, VERB_CANCELED, getLogIdsForHunter(hunter),
"all actions paused");
}
}
}
}
void performResumeTag(Object tag) {
// Trying to resume a tag that is not paused.
if (!pausedTags.remove(tag)) {
return;
}
List<Action> batch = null;
for (Iterator<Action> i = pausedActions.values().iterator(); i.hasNext();) {
Action action = i.next();
if (action.getTag().equals(tag)) {
if (batch == null) {
batch = new ArrayList<Action>();
}
batch.add(action);
i.remove();
}
}
if (batch != null) {
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(
REQUEST_BATCH_RESUME, batch));
}
}
void performRetry(BitmapHunter hunter) {
if (hunter.isCancelled())
return;
if (service.isShutdown()) {
performError(hunter, false);
return;
}
NetworkInfo networkInfo = null;
if (scansNetworkChanges) {
ConnectivityManager connectivityManager = getService(context,
CONNECTIVITY_SERVICE);
networkInfo = connectivityManager.getActiveNetworkInfo();
}
boolean hasConnectivity = networkInfo != null && networkInfo.isConnected();
boolean shouldRetryHunter = hunter.shouldRetry(airplaneMode, networkInfo);
boolean supportsReplay = hunter.supportsReplay();
if (!shouldRetryHunter) {
// Mark for replay only if we observe network info changes and support
// replay.
boolean willReplay = scansNetworkChanges && supportsReplay;
performError(hunter, willReplay);
if (willReplay) {
markForReplay(hunter);
}
return;
}
// If we don't scan for network changes (missing permission) or if we have
// connectivity, retry.
if (!scansNetworkChanges || hasConnectivity) {
if (hunter.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_RETRYING, getLogIdsForHunter(hunter));
}
hunter.future = service.submit(hunter);
return;
}
performError(hunter, supportsReplay);
if (supportsReplay) {
markForReplay(hunter);
}
}
void performComplete(BitmapHunter hunter) {
if (shouldWriteToMemoryCache(hunter.getMemoryPolicy())) {
cache.set(hunter.getKey(), hunter.getResult());
}
hunterMap.remove(hunter.getKey());
batch(hunter);
if (hunter.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_BATCHED, getLogIdsForHunter(hunter),
"for completion");
}
}
void performBatchComplete() {
List<BitmapHunter> copy = new ArrayList<BitmapHunter>(batch);
batch.clear();
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(
HUNTER_BATCH_COMPLETE, copy));
logBatch(copy);
}
void performError(BitmapHunter hunter, boolean willReplay) {
if (hunter.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_BATCHED, getLogIdsForHunter(hunter),
"for error" + (willReplay ? " (will replay)" : ""));
}
hunterMap.remove(hunter.getKey());
batch(hunter);
}
void performAirplaneModeChange(boolean airplaneMode) {
this.airplaneMode = airplaneMode;
}
void performNetworkStateChange(NetworkInfo info) {
if (service instanceof PicassoExecutorService) {
((PicassoExecutorService) service).adjustThreadCount(info);
}
// Intentionally check only if isConnected() here before we flush out failed
// actions.
if (info != null && info.isConnected()) {
flushFailedActions();
}
}
其他的有兴趣看看源码。