您的位置:首页 > 其它

Picasso分析04

2015-10-03 20:05 585 查看

1 BitmapHunter

一个BitmapHunter对应一个图片请求,可以包含多个Action,这些Action的getKey()值是相同的,

即对同一个图片,同时可能有多个在等待下载使用。即一个请求多个响应。

BitmapHunter只负责去获取图片然后回调通知Dispatch,其余的不负责。

使用到了RequestHandler和Request,Action

class BitmapHunter implements Runnable { // run函数
/** 同步解码--
* Global lock for bitmap decoding to ensure that we are only are decoding one at a time. Since
* this will only ever happen in background threads we help avoid excessive memory thrashing as
* well as potential OOMs. Shamelessly stolen from Volley.
*/
private static final Object DECODE_LOCK = new Object();

private static final ThreadLocal<StringBuilder> NAME_BUILDER = new ThreadLocal<StringBuilder>() {
@Override protected StringBuilder initialValue() {
return new StringBuilder(Utils.THREAD_PREFIX);
}
};

private static final AtomicInteger SEQUENCE_GENERATOR = new AtomicInteger();

private static final RequestHandler ERRORING_HANDLER = new RequestHandler() { // error handler
@Override public boolean canHandleRequest(Request data) {
return true;
}

@Override public Result load(Request request, int networkPolicy) throws IOException {
throw new IllegalStateException("Unrecognized type of request: " + request);
}
};

final int sequence;
final Picasso picasso;
final Dispatcher dispatcher;
final Cache cache;
final Stats stats;
final String key;
final Request data;
final int memoryPolicy;
int networkPolicy;
final RequestHandler requestHandler;

Action action;
List<Action> actions;
Bitmap result;
Future<?> future;
Picasso.LoadedFrom loadedFrom;
Exception exception;
int exifOrientation; // Determined during decoding of original resource.
int retryCount;
Priority priority;

PPBitmapHunter(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
Action action, RequestHandler requestHandler) {
this.sequence = SEQUENCE_GENERATOR.incrementAndGet(); //AtomicInteger
this.picasso = picasso;
this.dispatcher = dispatcher;
this.cache = cache;
this.stats = stats;
this.action = action;
this.key = action.getKey();
this.data = action.getRequest();
this.priority = action.getPriority();
this.memoryPolicy = action.getMemoryPolicy();
this.networkPolicy = action.getNetworkPolicy();
this.requestHandler = requestHandler;
this.retryCount = requestHandler.getRetryCount();
}

/**
* Decode a byte stream into a Bitmap. This method will take into account additional
*  information about the supplied request in order to do the decoding efficiently (such as
*  through leveraging {@code inSampleSize}).
*  leveraging--- leverage的现在分词, 促使…改变
*/
static Bitmap decodeStream(InputStream stream, Request request) throws IOException {
MarkableInputStream markStream = new MarkableInputStream(stream);
stream = markStream;
// 保存markStream的当前位置,最多缓存65536,多了之后mark标记会失效
long mark = markStream.savePosition(65536); // TODO fix this crap废话.mark为当前的偏移量的值
final BitmapFactory.Options options = RequestHandler.createBitmapOptions(request);//产生option
final boolean calculateSize = RequestHandler.requiresInSampleSize(options);//是否要计算大小
boolean isWebPFile = Utils.isWebPFile(stream); // 读取了stream,因此位置变化了
boolean isPurgeable = request.purgeable && android.os.Build.VERSION.SDK_INT < 21;
markStream.reset(mark); // 恢复到读取之前的状态,重复读取
// We decode from a byte array because, a) when decoding a WebP network stream, BitmapFactory
// throws a JNI Exception, so we workaround by decoding a byte array, or b) user requested
// purgeable, which only affects bitmaps decoded from byte arrays.!!!
if (isWebPFile || isPurgeable) {
byte[] bytes = Utils.toByteArray(stream);
if (calculateSize) {
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);//计算大小存于options
RequestHandler.calculateInSampleSize(request.targetWidth, request.targetHeight, options,
request);//计算比例
}
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);//解码byteArray
} else {
if (calculateSize) {
BitmapFactory.decodeStream(stream, null, options);
RequestHandler.calculateInSampleSize(request.targetWidth, request.targetHeight, options,
request);
markStream.reset(mark);//这里用的是stream,因此需要恢复
}
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
if (bitmap == null) {
// Treat null as an IO exception, we will eventually retry.
throw new IOException("Failed to decode stream.");
}
return bitmap;
}
}

static void updateThreadName(Request data) {
String name = data.getName();
StringBuilder builder = NAME_BUILDER.get();
builder.ensureCapacity(Utils.THREAD_PREFIX.length() + name.length());
builder.replace(Utils.THREAD_PREFIX.length(), builder.length(), name);//replace!
Thread.currentThread().setName(builder.toString());
}
@Override public void run() {
try {
updateThreadName(data);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this)); //executing
}
result = hunt(); //do the execute work now

if (result == null) {
dispatcher.dispatchFailed(this);
} else {
dispatcher.dispatchComplete(this);
}
} catch (Downloader.ResponseException e) {//自定义
if (!e.localCacheOnly || e.responseCode != 504) {//504这是代表着网关超时是现象出现了
exception = e;
}
dispatcher.dispatchFailed(this);
} catch (NetworkRequestHandler.ContentLengthException e) {//自定义
exception = e;
dispatcher.dispatchRetry(this); // 需要retry的情况,在网络错误时,注意使用的是dispatcher
} catch (IOException e) {
exception = e;
dispatcher.dispatchRetry(this);// 需要retry的情况,在读取错误时
} catch (OutOfMemoryError e) { // !!!
StringWriter writer = new StringWriter();
stats.createSnapshot().dump(new PrintWriter(writer));
exception = new RuntimeException(writer.toString(), e); // !!study
dispatcher.dispatchFailed(this);
} catch (Exception e) {
exception = e;
dispatcher.dispatchFailed(this);
} finally {
Thread.currentThread().setName(Utils.THREAD_IDLE_NAME); // ?
}
}

Bitmap hunt() throws IOException {
Bitmap bitmap = null;
if (shouldReadFromMemoryCache(memoryPolicy)) { //从缓存中获取
bitmap = cache.get(key);
if (bitmap != null) {
stats.dispatchCacheHit();
loadedFrom = MEMORY;
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache"); //decode
}
return bitmap;
}
}
// retryCount为0表示从本地获取,只有网络的才不为0
data.networkPolicy = retryCount == 0 ? NetworkPolicy.OFFLINE.index : networkPolicy;
RequestHandler.Result result = requestHandler.load(data, networkPolicy);//获取图片
if (result != null) { // 判断结果
loadedFrom = result.getLoadedFrom();
exifOrientation = result.getExifOrientation();
bitmap = result.getBitmap();
// If there was no Bitmap then we need to decode it from the stream.
if (bitmap == null) {
InputStream is = result.getStream();
try {
bitmap = decodeStream(is, data); // 前面分析的函数
} finally {
Utils.closeQuietly(is);
}
}
}
if (bitmap != null) {
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId()); // decoded代表bitmap获取成功
}
stats.dispatchBitmapDecoded(bitmap);
if (data.needsTransformation() || exifOrientation != 0) {
synchronized (DECODE_LOCK) { // 同一时刻只做一个图片的转换工作,属于类的锁
if (data.needsMatrixTransform() || exifOrientation != 0) {//第一次转换
bitmap = transformResult(data, bitmap, exifOrientation);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());
}
}
if (data.hasCustomTransformations()) { // 第二次转换
bitmap = applyCustomTransformations(data.transformations, bitmap);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(), "from custom transformations");
}
}
}
if (bitmap != null) {
stats.dispatchBitmapTransformed(bitmap);
}
}
}
return bitmap;
}

void attach(Action action) {
boolean loggingEnabled = picasso.loggingEnabled;
Request request = action.request;
if (this.action == null) {
this.action = action;
if (loggingEnabled) {
if (actions == null || actions.isEmpty()) {
log(OWNER_HUNTER, VERB_JOINED, request.logId(), "to empty hunter");
} else {
log(OWNER_HUNTER, VERB_JOINED, request.logId(), getLogIdsForHunter(this, "to "));
}
}
return;
}
if (actions == null) {
actions = new ArrayList<Action>(3);
}
actions.add(action);
if (loggingEnabled) {
log(OWNER_HUNTER, VERB_JOINED, request.logId(), getLogIdsForHunter(this, "to "));
}
Priority actionPriority = action.getPriority();
if (actionPriority.ordinal() > priority.ordinal()) { // 优先级的维护,使用最高的
priority = actionPriority;
}
}

void detach(Action action) {
boolean detached = false;
if (this.action == action) {
this.action = null;
detached = true;
} else if (actions != null) {
detached = actions.remove(action);
}
// The action being detached had the highest priority. Update this
// hunter's priority with the remaining actions.
if (detached && action.getPriority() == priority) {
priority = computeNewPriority();// 重新计算最高的优先级
}
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_REMOVED, action.request.logId(), getLogIdsForHunter(this, "from "));
}
}

private Priority computeNewPriority() { // 重新计算最高的优先级
Priority newPriority = LOW;
boolean hasMultiple = actions != null && !actions.isEmpty();
boolean hasAny = action != null || hasMultiple;
// Hunter has no requests, low priority.
if (!hasAny) {
return newPriority;
}
if (action != null) {
newPriority = action.getPriority();
}
if (hasMultiple) {
//noinspection ForLoopReplaceableByForEach
for (int i = 0, n = actions.size(); i < n; i++) {
Priority actionPriority = actions.get(i).getPriority();
if (actionPriority.ordinal() > newPriority.ordinal()) {
newPriority = actionPriority;
}
}
}
return newPriority;
}

boolean cancel() {
return action == null
&& (actions == null || actions.isEmpty())
&& future != null
&& future.cancel(false);
// 在submit时hunter.future = service.submit(hunter);类型为PicassoFutureTask--FutureTask
}

boolean isCancelled() {
return future != null && future.isCancelled();
}

boolean shouldRetry(boolean airplaneMode, NetworkInfo info) {
boolean hasRetries = retryCount > 0;
if (!hasRetries) {
return false;
}
retryCount--;
return requestHandler.shouldRetry(airplaneMode, info);
}
// 类似于builder的功能 !!!!!!!!!!!!!!!!!
static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache,
Stats stats, Action action) {
Request request = action.getRequest();
List<AARequestHandler> requestHandlers = picasso.getRequestHandlers();

// Index-based loop to avoid allocating an iterator.
//noinspection ForLoopReplaceableByForEach
for (int i = 0, count = requestHandlers.size(); i < count; i++) {
RequestHandler requestHandler = requestHandlers.get(i);
if (requestHandler.canHandleRequest(request)) {  // 找到对应的requestHandler去处理这个Request
return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);
}
}
return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
}
// 自定义的转换器
static Bitmap applyCustomTransformations(List<Transformation> transformations, Bitmap result) {
for (int i = 0, count = transformations.size(); i < count; i++) {
final ITransformation transformation = transformations.get(i);
Bitmap newResult;
try { // 调用变换接口对图片进行处理,注意新旧bitmap的回收问题,见接口函数transform说明
newResult = transformation.transform(result);
} catch (final RuntimeException e) {
Picasso.HANDLER.post(new Runnable() {
@Override public void run() {
throw new RuntimeException(
"Transformation " + transformation.key() + " crashed with exception.", e);
}
});
return null;
}

if (newResult == null) {
final StringBuilder builder = new StringBuilder() //
.append("Transformation ")
.append(transformation.key())
.append(" returned null after ")
.append(i)
.append(" previous transformation(s).\n\nTransformation list:\n");
for (ITransformation t : transformations) {
builder.append(t.key()).append('\n');
}
Picasso.HANDLER.post(new Runnable() {
@Override public void run() {
throw new NullPointerException(builder.toString());
}
});
return null;
}

if (newResult == result && result.isRecycled()) {// 回收错误
Picasso.HANDLER.post(new Runnable() {
@Override public void run() {
throw new IllegalStateException("Transformation "
+ transformation.key()
+ " returned input Bitmap but recycled it.");
}
});
return null;
}

// If the transformation returned a new bitmap ensure they recycled the original.
if (newResult != result && !result.isRecycled()) {// 回收错误
Picasso.HANDLER.post(new Runnable() {
@Override public void run() {
throw new IllegalStateException("Transformation "
+ transformation.key()
+ " mutated input Bitmap but failed to recycle the original.");
}
});
return null;
}
result = newResult;
}
return result;
}

static Bitmap transformResult(Request data, Bitmap result, int exifOrientation) {
int inWidth = result.getWidth();
int inHeight = result.getHeight();
boolean onlyScaleDown = data.onlyScaleDown;
int drawX = 0;
int drawY = 0;
int drawWidth = inWidth;
int drawHeight = inHeight;

Matrix matrix = new Matrix();
if (data.needsMatrixTransform() || exifOrientation != 0) {
int targetWidth = data.targetWidth;
int targetHeight = data.targetHeight;
float targetRotation = data.rotationDegrees;
if (targetRotation != 0) {
double cosR = Math.cos(Math.toRadians(targetRotation));
double sinR = Math.sin(Math.toRadians(targetRotation));
if (data.hasRotationPivot) { //不同版本中修改了
matrix.setRotate(targetRotation, data.rotationPivotX, data.rotationPivotY);
// Recalculate dimensions after rotation around pivot point
// 公式http://jingyan.baidu.com/article/2c8c281dfbf3dd0009252a7b.html
double x1T = data.rotationPivotX * (1.0 - cosR) + (data.rotationPivotY * sinR);
double y1T = data.rotationPivotY * (1.0 - cosR) - (data.rotationPivotX * sinR);
double x2T = x1T + (data.targetWidth * cosR);
double y2T = y1T + (data.targetWidth * sinR);
double x3T = x1T + (data.targetWidth * cosR) - (data.targetHeight * sinR);
double y3T = y1T + (data.targetWidth * sinR) + (data.targetHeight * cosR);
double x4T = x1T - (data.targetHeight * sinR);
double y4T = y1T + (data.targetHeight * cosR);

double maxX = Math.max(x4T, Math.max(x3T, Math.max(x1T, x2T)));
double minX = Math.min(x4T, Math.min(x3T, Math.min(x1T, x2T)));
double maxY = Math.max(y4T, Math.max(y3T, Math.max(y1T, y2T)));
double minY = Math.min(y4T, Math.min(y3T, Math.min(y1T, y2T)));
targetWidth = (int) Math.floor(maxX - minX);
targetHeight  = (int) Math.floor(maxY - minY);
} else {
matrix.setRotate(targetRotation);
// Recalculate dimensions after rotation (around origin)
double x1T = 0.0;
double y1T = 0.0;
double x2T = (data.targetWidth * cosR); // 见下图说明
double y2T = (data.targetWidth * sinR); // 见下图说明
double x3T = (data.targetWidth * cosR) - (data.targetHeight * sinR);//数学计算
double y3T = (data.targetWidth * sinR) + (data.targetHeight * cosR);//数学计算
double x4T = -(data.targetHeight * sinR);//数学计算
double y4T = (data.targetHeight * cosR);//数学计算

double maxX = Math.max(x4T, Math.max(x3T, Math.max(x1T, x2T)));
double minX = Math.min(x4T, Math.min(x3T, Math.min(x1T, x2T)));
double maxY = Math.max(y4T, Math.max(y3T, Math.max(y1T, y2T)));
double minY = Math.min(y4T, Math.min(y3T, Math.min(y1T, y2T)));
targetWidth = (int) Math.floor(maxX - minX);
targetHeight  = (int) Math.floor(maxY - minY);
}
}

// EXIf interpretation should be done before cropping in case the dimensions need to
// be recalculated
if (exifOrientation != 0) { // 见第一篇的图解
int exifRotation = getExifRotation(exifOrientation);
int exifTranslation = getExifTranslation(exifOrientation);
if (exifRotation != 0) {
matrix.preRotate(exifRotation);
if (exifRotation == 90 || exifRotation == 270) {
// Recalculate dimensions after exif rotation
int tmpHeight = targetHeight;
targetHeight = targetWidth;
targetWidth = tmpHeight;
}
}
if (exifTranslation != 1) {
matrix.postScale(exifTranslation, 1);
}
}

if (data.centerCrop) {
// Keep aspect ratio if one dimension is set to 0
float widthRatio =
targetWidth != 0 ? targetWidth / (float) inWidth : targetHeight / (float) inHeight;
float heightRatio = // targetHeight不为0时,等于targetHeight / (float) inHeight
targetHeight != 0 ? targetHeight / (float) inHeight : targetWidth / (float) inWidth;
float scaleX, scaleY;
if (widthRatio > heightRatio) { // newSize = targetHeight / widthRatio
// 因为高度也会按照widthRatio比率去放大,会超越实际的高度的,但centerCrop是要将多余的截取掉的,
// 而放大缩小都以inHeight为计算基础的,因此inHeight*widthRatio为放大后的,肯定多了,需要减少。
// 为了满足放大widthRatio后的值可以填充满targetHeight,因此将对原始的图片进行部分的放大处理,这样
// 可以使得放大后正好满足targetHeight,即newSize代表需要从原始图片截取的高度,目标高度为targetHeight,
// 放大比率为widthRatio,而 newSize * widthRatio就是targetHeight了!!!
// drawY代表从何处开始截图,因为用inHeight去放大会大于目标的高度,因此从中间截图比较好!!!!
int newSize = (int) Math.ceil(inHeight * (heightRatio / widthRatio));
drawY = (inHeight - newSize) / 2;
drawHeight = newSize;// drawHeight = targetHeight / widthRatio
scaleX = widthRatio;
scaleY = targetHeight / (float) drawHeight; // scaleY = widthRatio
// 逗我玩嘛?为了取一些中间值如drawY 和 drawHeight
} else if (widthRatio < heightRatio) {
int newSize = (int) Math.ceil(inWidth * (widthRatio / heightRatio));
drawX = (inWidth - newSize) / 2;
drawWidth = newSize;
scaleX = targetWidth / (float) drawWidth;
scaleY = heightRatio;
} else {
drawX = 0;
drawWidth = inWidth;
scaleX = scaleY = heightRatio;
}
if (shouldResize(onlyScaleDown, inWidth, inHeight, targetWidth, targetHeight)) {
matrix.preScale(scaleX, scaleY);
}
} else if (data.centerInside) {
// Keep aspect ratio if one dimension is set to 0
float widthRatio =
targetWidth != 0 ? targetWidth / (float) inWidth : targetHeight / (float) inHeight;
float heightRatio =
targetHeight != 0 ? targetHeight / (float) inHeight : targetWidth / (float) inWidth;
float scale = widthRatio < heightRatio ? widthRatio : heightRatio;
if (shouldResize(onlyScaleDown, inWidth, inHeight, targetWidth, targetHeight)) {
matrix.preScale(scale, scale);
}
} else if ((targetWidth != 0 || targetHeight != 0) //
&& (targetWidth != inWidth || targetHeight != inHeight)) {
// If an explicit target size has been specified and they do not match the results bounds,
// pre-scale the existing matrix appropriately.
// Keep aspect ratio if one dimension is set to 0.
float sx =
targetWidth != 0 ? targetWidth / (float) inWidth : targetHeight / (float) inHeight;
float sy =
targetHeight != 0 ? targetHeight / (float) inHeight : targetWidth / (float) inWidth;
if (shouldResize(onlyScaleDown, inWidth, inHeight, targetWidth, targetHeight)) {
matrix.preScale(sx, sy);
}
}
}

Bitmap newResult =
Bitmap.createBitmap(result, drawX, drawY, drawWidth, drawHeight, matrix, true);
if (newResult != result) {
result.recycle();
result = newResult;
}

return result;
}

private static boolean shouldResize(boolean onlyScaleDown, int inWidth, int inHeight,
int targetWidth, int targetHeight) {
return !onlyScaleDown || inWidth > targetWidth || inHeight > targetHeight;
}

static int getExifRotation(int orientation) {
int rotation;
switch (orientation) {
case ORIENTATION_ROTATE_90:
case ORIENTATION_TRANSPOSE:
rotation = 90;
break;
case ORIENTATION_ROTATE_180:
case ORIENTATION_FLIP_VERTICAL:
rotation = 180;
break;
case ORIENTATION_ROTATE_270:
case ORIENTATION_TRANSVERSE:
rotation = 270;
break;
default:
rotation = 0;
}
return rotation;
}

static int getExifTranslation(int orientation)  {
int translation;
switch (orientation) {
case ORIENTATION_FLIP_HORIZONTAL:
case ORIENTATION_FLIP_VERTICAL:
case ORIENTATION_TRANSPOSE:
case ORIENTATION_TRANSVERSE:
translation = -1;
break;
default:
translation = 1;
}
return translation;
}
}




2 Dispatcher

维护了一堆BitmapHunter

有专门的dispatch线程,负责同步增删改查BitmapHunter,网络监听,飞行模式等等

class Dispatcher {
private static final int RETRY_DELAY = 500;
private static final int AIRPLANE_MODE_ON = 1;
private static final int AIRPLANE_MODE_OFF = 0;

static final int REQUEST_SUBMIT = 1; // request
static final int REQUEST_CANCEL = 2;
static final int REQUEST_GCED = 3;
static final int HUNTER_COMPLETE = 4; // hunter
static final int HUNTER_RETRY = 5;
static final int HUNTER_DECODE_FAILED = 6;
static final int HUNTER_DELAY_NEXT_BATCH = 7;
static final int HUNTER_BATCH_COMPLETE = 8;
static final int NETWORK_STATE_CHANGE = 9;
static final int AIRPLANE_MODE_CHANGE = 10;
static final int TAG_PAUSE = 11;
static final int TAG_RESUME = 12;
static final int REQUEST_BATCH_RESUME = 13;

private static final String DISPATCHER_THREAD_NAME = "Dispatcher";
private static final int BATCH_DELAY = 200; // ms

final DispatcherThread dispatcherThread; // HandlerThread
final Context context;
final ExecutorService service;
final Downloader downloader;
final Map<String, BitmapHunter> hunterMap;
final Map<Object, Action> failedActions;
final Map<Object, Action> pausedActions;
final Set<Object> pausedTags;
final Handler handler;
final Handler mainThreadHandler;
final Cache cache;
final Stats stats;
final List<BitmapHunter> batch;
final NetworkBroadcastReceiver receiver;
final boolean scansNetworkChanges;

boolean airplaneMode;

Dispatcher(Context context, ExecutorService service, Handler mainThreadHandler,
Downloader downloader, Cache cache, Stats stats) {
this.dispatcherThread = new DispatcherThread();
this.dispatcherThread.start();
Utils.flushStackLocalLeaks(dispatcherThread.getLooper());
this.context = context;
this.service = service;
this.hunterMap = new LinkedHashMap<String, PPBitmapHunter>();
this.failedActions = new WeakHashMap<Object, BBAction>();
this.pausedActions = new WeakHashMap<Object, BBAction>();
this.pausedTags = new HashSet<Object>();
this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this);
this.downloader = downloader;
this.mainThreadHandler = mainThreadHandler;
this.cache = cache;
this.stats = stats;
this.batch = new ArrayList<BitmapHunter>(4);
this.airplaneMode = Utils.isAirplaneModeOn(this.context);
this.scansNetworkChanges = hasPermission(context, Manifest.permission.ACCESS_NETWORK_STATE);
this.receiver = new NetworkBroadcastReceiver(this);
receiver.register();
}

void shutdown() {
// Shutdown the thread pool only if it is the one created by Picasso.
if (service instanceof PicassoExecutorService) {
service.shutdown(); // 线程池shut
}
downloader.shutdown(); // close cache
dispatcherThread.quit(); // Quits the handler thread's looper.
// Unregister network broadcast receiver on the main thread. 主线程操作广播
Picasso.HANDLER.post(new Runnable() {
@Override public void run() {
receiver.unregister();
}
});
}
// 发送命令消息使用dispatch+命令,而处理消息使用perform+命令
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));  }

void performSubmit(Action action) {    performSubmit(action, true);  }
void performSubmit(Action action, boolean dismissFailed) {
//dismissFailed:false表示failedActions中已经删除了,不用再去删了,true则要去删
// 注意几个参数:action.getTag();action.getTarget();action.getKey()
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()); // key值对应hunter
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
hunter.future = service.submit(hunter);// 提交一个runnable--
// ---PicassoFutureTask ftask = new PicassoFutureTask((PPBitmapHunter) task);
// ---execute(ftask);---return ftask; 其中execute (Runnable command),返回的ftask包含了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);//去除其中一个Action,这个不需要回调了哦
if (hunter.cancel()) { // 判断这个hunter中是否还有Action
hunterMap.remove(key);// 已经没有啦,如果正在hunt也没关系,因为设置cancel了的标志
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)) {//true if this set is modified, false otherwise
return;
}
// Go through all active hunters and detach/pause the requests
// that have the paused tag.
for (Iterator<PPBitmapHunter> it = hunterMap.values().iterator(); it.hasNext();) {
PPBitmapHunter hunter = it.next();
boolean loggingEnabled = hunter.getPicasso().loggingEnabled;
BBAction single = hunter.getAction();
List<BBAction> 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--) {
BBAction 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) {//重新执行暂停的action
// Trying to resume a tag that is not paused.
if (!pausedTags.remove(tag)) {
return;
}
List<BBAction> batch = null;
for (Iterator<BBAction> i = pausedActions.values().iterator(); i.hasNext();) {
BBAction action = i.next();
if (action.getTag().equals(tag)) {
if (batch == null) {
batch = new ArrayList<BBAction>();
}
batch.add(action);
i.remove();
}
}
if (batch != null) {// 让主线去判断处理新的Action
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(REQUEST_BATCH_RESUME, batch));
}
}

void performRetry(BitmapHunter hunter) { //注意是针对网络的情况
if (hunter.isCancelled()) return;
if (service.isShutdown()) {//!!!重试时确认线程池还在呢
performError(hunter, false);//main--HUNTER_BATCH_COMPLETE
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);//默认都是false除了网络
boolean supportsReplay = hunter.supportsReplay();//默认都是false除了网络
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); //failedActions.put()标记为replay
}
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));
}
//noinspection ThrowableResultOfMethodCallIgnored
if (hunter.getException() instanceof AANetworkRequestHandler.ContentLengthException) {
hunter.networkPolicy |= NetworkPolicy.NO_CACHE.index;
}
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);//进行批处理这个hunter中的Actions
if (hunter.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_BATCHED, getLogIdsForHunter(hunter), "for completion");
}
}

void performBatchComplete() {//通知主线程
List<PPBitmapHunter> copy = new ArrayList<PPBitmapHunter>(batch);
batch.clear();
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
logBatch(copy);
}

void performError(BitmapHunter hunter, boolean willReplay) {//图片处理失败和成功的逻辑一样哦
if (hunter.getPicasso().loggingEnabled) { // willReplay表示已经存于failedActions
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();//网络可用了,去重新尝试failedActions中的Action
}
}

private void flushFailedActions() {
if (!failedActions.isEmpty()) {
Iterator<BBAction> iterator = failedActions.values().iterator();
while (iterator.hasNext()) {
BBAction action = iterator.next();
iterator.remove();
if (action.getPicasso().loggingEnabled) {
log(OWNER_DISPATCHER, VERB_REPLAYING, action.getRequest().logId());
}
performSubmit(action, false);// false表示failedActions中已经删除了,不用再去删了
}
}
}

private void markForReplay(PPBitmapHunter hunter) {//标记为可以再次重试获取
BBAction action = hunter.getAction();
if (action != null) {
markForReplay(action);
}
List<BBAction> joined = hunter.getActions();
if (joined != null) {
//noinspection ForLoopReplaceableByForEach
for (int i = 0, n = joined.size(); i < n; i++) {
BBAction join = joined.get(i);
markForReplay(join);
}
}
}

private void markForReplay(BBAction action) {//标记并存储,供以后调用重试
Object target = action.getTarget();
if (target != null) {
action.willReplay = true;
failedActions.put(target, action);
}
}

private void batch(BitmapHunter hunter) {//hunter操作成功或error
if (hunter.isCancelled()) {
return;
}
batch.add(hunter);
if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {
handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);
}
}

private void logBatch(List<BitmapHunter> copy) {
if (copy == null || copy.isEmpty()) return;
PPBitmapHunter hunter = copy.get(0);
Picasso picasso = hunter.getPicasso();
if (picasso.loggingEnabled) {
StringBuilder builder = new StringBuilder();
for (BitmapHunter bitmapHunter : copy) {
if (builder.length() > 0) builder.append(", ");
builder.append(Utils.getLogIdsForHunter(bitmapHunter));
}
log(OWNER_DISPATCHER, VERB_DELIVERED, builder.toString());
}
}

private static class DispatcherHandler extends Handler {
private final Dispatcher dispatcher;
public DispatcherHandler(Looper looper, PPDispatcher dispatcher) {
super(looper);
this.dispatcher = dispatcher;
}
@Override public void handleMessage(final Message msg) {
switch (msg.what) {
case REQUEST_SUBMIT: {
BBAction action = (BBAction) msg.obj;
dispatcher.performSubmit(action);
break;
}
case REQUEST_CANCEL: {
BBAction action = (BBAction) 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: {
PPBitmapHunter hunter = (PPBitmapHunter) msg.obj;
dispatcher.performComplete(hunter);
break;
}
case HUNTER_RETRY: {
PPBitmapHunter hunter = (PPBitmapHunter) msg.obj;
dispatcher.performRetry(hunter);
break;
}
case HUNTER_DECODE_FAILED: {
PPBitmapHunter hunter = (PPBitmapHunter) msg.obj;
dispatcher.performError(hunter, false);
break;
}
case HUNTER_DELAY_NEXT_BATCH: {//hunter操作成功或error
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);
}
});
}
}
}

static class DispatcherThread extends HandlerThread {
DispatcherThread() {
super(Utils.THREAD_PREFIX + DISPATCHER_THREAD_NAME, THREAD_PRIORITY_BACKGROUND);
}
}
// 监听网络广播---飞行模式
static class NetworkBroadcastReceiver extends BroadcastReceiver {
static final String EXTRA_AIRPLANE_STATE = "state";
private final Dispatcher dispatcher;
NetworkBroadcastReceiver(Dispatcher dispatcher) {
this.dispatcher = dispatcher;
}
void register() {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_AIRPLANE_MODE_CHANGED);
if (dispatcher.scansNetworkChanges) {
filter.addAction(CONNECTIVITY_ACTION);
}
dispatcher.context.registerReceiver(this, filter);
}
void unregister() {
dispatcher.context.unregisterReceiver(this);
}

@Override public void onReceive(Context context, Intent intent) {
// On some versions of Android this may be called with a null Intent,
// also without extras (getExtras() == null), in such case we use defaults.
if (intent == null) { !!!
return;
}
final String action = intent.getAction();
if (ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
if (!intent.hasExtra(EXTRA_AIRPLANE_STATE)) {
return; // No airplane state, ignore it. Should we query Utils.isAirplaneModeOn?
}
dispatcher.dispatchAirplaneModeChange(intent.getBooleanExtra(EXTRA_AIRPLANE_STATE, false));
} else if (CONNECTIVITY_ACTION.equals(action)) {
ConnectivityManager connectivityManager = getService(context, CONNECTIVITY_SERVICE);
dispatcher.dispatchNetworkStateChange(connectivityManager.getActiveNetworkInfo());
}
}
}
}


3 Picasso

Image downloading, transformation, and caching manager.
Use with(Context) for the global singleton instance or construct your own instance with Picasso.Builder.


public class Picasso {
public interface Listener {
/**
* Invoked when an image has failed to load. This is useful for reporting image failures to a
* remote analytics service, for example. 分析服务
*/
void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception);
}

/** CDN: Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定
性的瓶颈和环节,使内容传输的更快、更稳定。CDN加速
* A transformer that is called immediately before every request is submitted. This can be used
*  to modify any information about a request.For example, if you use a CDN you can change the
*  hostname for the image based on the current location of the user in order to get faster
*  download speeds.
*/
public interface RequestTransformer {
/**Transform a request before it is submitted to be processed.
* @return The original request or a new request to replace it. Must not be null.
*/
Request transformRequest(Request request);
}

/**The priority of a request. */
public enum Priority {
LOW,    NORMAL,    HIGH
}

static final String TAG = "Picasso";
static final Handler HANDLER = new Handler(Looper.getMainLooper()) {//主线程的handler
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case HUNTER_BATCH_COMPLETE: {
List<BitmapHunter> batch = (List<BitmapHunter>) msg.obj;
//noinspection ForLoopReplaceableByForEach
for (int i = 0, n = batch.size(); i < n; i++) {
PPBitmapHunter hunter = batch.get(i);
hunter.picasso.complete(hunter);
}
break;
}
case REQUEST_GCED: {//回收的意思吧
Action action = (Action) msg.obj;
if (action.getPicasso().loggingEnabled) {//cancel!!!
log(OWNER_MAIN, VERB_CANCELED, action.request.logId(), "target got garbage collected");
}
action.picasso.cancelExistingRequest(action.getTarget());
break;
}
case REQUEST_BATCH_RESUME:
List<BBAction> batch = (List<BBAction>) msg.obj;
//noinspection ForLoopReplaceableByForEach
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);
}    }
};

static volatile Picasso singleton = null;

private final Listener listener;
private final RequestTransformer requestTransformer;
private final CleanupThread cleanupThread; // 用于发送REQUEST_GCED消息
private final List<RequestHandler> requestHandlers;

final Context context;
final Dispatcher dispatcher;
final Cache cache;
final Stats stats;
final Map<Object, Action> targetToAction;
final Map<ImageView, DeferredRequestCreator> targetToDeferredRequestCreator;
final ReferenceQueue<Object> referenceQueue;
final Bitmap.Config defaultBitmapConfig;

boolean indicatorsEnabled;
volatile boolean loggingEnabled;
boolean shutdown;

Picasso(Context context, PPDispatcher dispatcher, ICache cache, Listener listener,
RequestTransformer requestTransformer, List<AARequestHandler> 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;
this.defaultBitmapConfig = defaultBitmapConfig;

int builtInHandlers = 7; // Adjust this as internal handlers are added or removed.共7个
int extraCount = (extraRequestHandlers != null ? extraRequestHandlers.size() : 0);
List<RequestHandler> allRequestHandlers =
new ArrayList<RequestHandler>(builtInHandlers + extraCount);
// ResourceRequestHandler needs to be the first in the list to avoid
// forcing other RequestHandlers to perform null checks on request.uri
// to cover the (request.resourceId != 0) case.
allRequestHandlers.add(new AAResourceRequestHandler(context));
if (extraRequestHandlers != null) {
allRequestHandlers.addAll(extraRequestHandlers);
} // 依次添加对应的RequestHandler
allRequestHandlers.add(new AAContactsPhotoRequestHandler(context));
allRequestHandlers.add(new AAMediaStoreRequestHandler(context));
allRequestHandlers.add(new AAContentStreamRequestHandler(context));
allRequestHandlers.add(new AAAssetRequestHandler(context));
allRequestHandlers.add(new AAFileRequestHandler(context));
allRequestHandlers.add(new AANetworkRequestHandler(dispatcher.downloader, stats));
requestHandlers = Collections.unmodifiableList(allRequestHandlers);

this.stats = stats;
this.targetToAction = new WeakHashMap<Object, BBAction>(); // WeakHashMap!!!
this.targetToDeferredRequestCreator = new WeakHashMap<ImageView, ZDeferredRequestCreator>();
this.indicatorsEnabled = indicatorsEnabled;
this.loggingEnabled = loggingEnabled;
this.referenceQueue = new ReferenceQueue<Object>();
this.cleanupThread = new CleanupThread(referenceQueue, HANDLER);
this.cleanupThread.start();
}

/**
* Cancel any existing requests for the specified RemoteViews target with the given   */
public void cancelRequest(RemoteViews remoteViews, int viewId) {//equals方法!!!
cancelExistingRequest(new RemoteViewsAction.RemoteViewsTarget(remoteViews, viewId));
}

/**
* Cancel any existing requests with given tag.    */
public void cancelTag(Object tag) {
checkMain();
if (tag == null) {
throw new IllegalArgumentException("Cannot cancel requests with null tag.");
}
List<BBAction> actions = new ArrayList<Action>(targetToAction.values());
//noinspection ForLoopReplaceableByForEach
for (int i = 0, n = actions.size(); i < n; i++) {
Action action = actions.get(i);
if (tag.equals(action.getTag())) {
cancelExistingRequest(action.getTarget());
}
}
List<DeferredRequestCreator> deferredRequestCreators =
new ArrayList<DeferredRequestCreator>(targetToDeferredRequestCreator.values());
//noinspection ForLoopReplaceableByForEach
for (int i = 0, n = deferredRequestCreators.size(); i < n; i++) {
DeferredRequestCreator deferredRequestCreator = deferredRequestCreators.get(i);
if (tag.equals(deferredRequestCreator.getTag())) {
deferredRequestCreator.cancel();
}
}
}

/**
* Pause existing requests with the given tag. */
public void pauseTag(Object tag) {
dispatcher.dispatchPauseTag(tag);
}

/**Start an image request using the specified path. This is a convenience method for calling
load(Uri).This path may be a remote URL, file resource (prefixed with file:), content resource
(prefixed with content:), or android resource (prefixed with android.resource:.
Passing null as a path will not trigger any request but will set a placeholder,
if one is specified.
*/
public RequestCreator load(String path) { // ...
if (path == null) {
return new RequestCreator(this, null, 0);
}
if (path.trim().length() == 0) {
throw new IllegalArgumentException("Path must not be empty.");
}
return load(Uri.parse(path));
}

/** Invalidate all memory cached images for the specified {@code uri}.   */
public void invalidate(Uri uri) { // ...
if (uri == null) {      throw new IllegalArgumentException("uri == null");    }
cache.clearKeyUri(uri.toString());
}

/** Stops this instance from accepting further requests. */
public void shutdown() {
if (this == singleton) { //?
throw new UnsupportedOperationException("Default singleton instance cannot be shutdown.");
}
if (shutdown) {
return;
}
cache.clear(); // 每个类都有一个结束的方法
cleanupThread.shutdown(); // targetToAction没有处理?因为dispatcher处理了
stats.shutdown();
dispatcher.shutdown();
for (DeferredRequestCreator deferredRequestCreator : targetToDeferredRequestCreator.values())
{      deferredRequestCreator.cancel();    }
targetToDeferredRequestCreator.clear();
shutdown = true;
}

void defer(ImageView view, DeferredRequestCreator request) {
// If there is already a deferred request, cancel it.
if (targetToDeferredRequestCreator.containsKey(view)) {
cancelExistingRequest(view);
}
targetToDeferredRequestCreator.put(view, request);
}

void enqueueAndSubmit(BBAction action) {
Object target = action.getTarget();
if (target != null && targetToAction.get(target) != action) {
// This will also check we are on the main thread.
cancelExistingRequest(target);
targetToAction.put(target, action);
}
submit(action);
}

void submit(BBAction action) {
dispatcher.dispatchSubmit(action);
}

Bitmap quickMemoryCacheCheck(String key) {// 从...
Bitmap cached = cache.get(key);
if (cached != null) {
stats.dispatchCacheHit();
} else {
stats.dispatchCacheMiss();
}
return cached;
}

void complete(BitmapHunter hunter) {
Action single = hunter.getAction();
List<Action> joined = hunter.getActions();
boolean hasMultiple = joined != null && !joined.isEmpty();
boolean shouldDeliver = single != null || hasMultiple;
if (!shouldDeliver) {
return;
}
Uri uri = hunter.getData().uri;
Exception exception = hunter.getException();//获取过程出现的异常
Bitmap result = hunter.getResult();
LoadedFrom from = hunter.getLoadedFrom();//获取成功后赋值的
if (single != null) {
deliverAction(result, from, single);
}
if (hasMultiple) {
//noinspection ForLoopReplaceableByForEach
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);//监听服务
}
}

void resumeAction(BBAction action) {
Bitmap bitmap = null;
if (shouldReadFromMemoryCache(action.memoryPolicy)) {
bitmap = quickMemoryCacheCheck(action.getKey());
}
if (bitmap != null) {
// Resumed action is cached, complete immediately.
deliverAction(bitmap, MEMORY, action);
if (loggingEnabled) {
log(OWNER_MAIN, VERB_COMPLETED, action.request.logId(), "from " + MEMORY);
}
} else {
// Re-submit the action to the executor.
enqueueAndSubmit(action);
if (loggingEnabled) {
log(OWNER_MAIN, VERB_RESUMED, action.request.logId());
}
}
}
// 处理Action,根据图片和来源
private void deliverAction(Bitmap result, LoadedFrom from, BBAction action) {
if (action.isCancelled()) {//已经取消
return;
}
if (!action.willReplay()) {//表明failedActions中存储了
targetToAction.remove(action.getTarget());
}
if (result != null) {
if (from == null) {
throw new AssertionError("LoadedFrom cannot be null.");
}
action.complete(result, from);
if (loggingEnabled) {
log(OWNER_MAIN, VERB_COMPLETED, action.request.logId(), "from " + from);
}
} else {
action.error();
if (loggingEnabled) {
log(OWNER_MAIN, VERB_ERRORED, action.request.logId());
}
}
}

private void cancelExistingRequest(Object target) {
checkMain();
BBAction action = targetToAction.remove(target);
if (action != null) {
action.cancel();//取消这个任务,之后即时获取成功也不会操作了
dispatcher.dispatchCancel(action);//去除对应Hunter下的这个Action
}
if (target instanceof ImageView) {
ImageView targetImageView = (ImageView) target;
DeferredRequestCreator deferredRequestCreator =
targetToDeferredRequestCreator.remove(targetImageView);
if (deferredRequestCreator != null) {
deferredRequestCreator.cancel();
}
}
}

/**
* When the target of an action is weakly reachable but the request hasn't been canceled, it
* gets added to the reference queue. This thread empties the reference queue and cancels the
* request.
*/
private static class CleanupThread extends Thread {
private final ReferenceQueue<Object> referenceQueue;
private final Handler handler;

CleanupThread(ReferenceQueue<Object> referenceQueue, Handler handler) {
this.referenceQueue = referenceQueue;
this.handler = handler;
setDaemon(true);
setName(THREAD_PREFIX + "refQueue");
}

@Override public void run() {
Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
while (true) {
try { // 解释和Utils中那个方法类似
// Prior to Android 5.0, even when there is no local variable, the result from
// remove() & obtainMessage() is kept as a stack local variable.
// We're forcing this reference to be cleared and replaced by looping every second
// when there is nothing to do.
// This behavior has been tested and reproduced with heap dumps.
RequestWeakReference<?> remove =
(RequestWeakReference<?>) referenceQueue.remove(THREAD_LEAK_CLEANING_MS);
Message message = handler.obtainMessage();
if (remove != null) {
message.what = REQUEST_GCED;
message.obj = remove.action;
handler.sendMessage(message);
} else {
message.recycle();
}
} catch (InterruptedException e) {
break;
} catch (final Exception e) {
handler.post(new Runnable() {
@Override public void run() {
throw new RuntimeException(e);
}
});
break;
}
}
}
//Posts an interrupt request to this Thread. The behavior depends on the state of this Thread:
/*Threads blocked in one of Object's wait() methods or one of Thread's join() or sleep() methods will be woken up, their interrupt status will be cleared,and they receive an InterruptedException
Threads blocked in an I/O operation of an InterruptibleChannel will have their interrupt status
set and receive an ClosedByInterruptException. Also, the channel will be closed.
Threads blocked in a Selector will have their interrupt status set and return immediately.
They don't receive an exception in this case.
*/
void shutdown() {
interrupt();
}
}

/**
The global default Picasso instance.
This instance is automatically initialized with defaults that are suitable to most implementations.
LRU memory cache of 15% the available application RAM
Disk cache of 2% storage space up to 50MB but no less than 5MB. (Note: this is only available on
API 14+ or if you are using a standalone library that provides a disk cache on all API levels
like OkHttp)
Three download threads for disk and network access.
If these settings do not meet the requirements of your application you can construct your own
with full control over the configuration by using Picasso.Builder to create a Picasso instance.
You can either use this directly or by setting it as the global instance with
setSingletonInstance.
*/
public static Picasso with(Context context) { // 单例!!!!!!!!!!!!!!!!!!!!!!
if (singleton == null) {
synchronized (Picasso.class) {
if (singleton == null) {
singleton = new Builder(context).build();
}
}
}
return singleton;
}

public static void setSingletonInstance(Picasso picasso) {
if (picasso == null) {      throw new IllegalArgumentException("Picasso must not be null.");
}
synchronized (Picasso.class) {
if (singleton != null) {
throw new IllegalStateException("Singleton instance already exists.");
}
singleton = picasso;
}
}

/** Fluent API for creating {@link Picasso} instances. */
public static class Builder { // 经纪人,对外提供配置以下变量的接口
private final Context context;
private Downloader downloader;
private ExecutorService service;
private Cache cache;
private Listener listener;
private RequestTransformer transformer;
private List<RequestHandler> requestHandlers;
private Bitmap.Config defaultBitmapConfig;

private boolean indicatorsEnabled;
private boolean loggingEnabled;

/** Start building a new {@link Picasso} instance. */
public Builder(Context context) {
if (context == null) {
throw new IllegalArgumentException("Context must not be null.");
}
this.context = context.getApplicationContext();//获取APP的context
}

/** Specify a listener for interesting events. */
public Builder listener(Listener listener) {
if (listener == null) {
throw new IllegalArgumentException("Listener must not be null.");
}
if (this.listener != null) {
throw new IllegalStateException("Listener already set.");
}
this.listener = listener;
return this;
}

/** Create the {@link Picasso} instance. */
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);
}
}

/** Describes where the image was loaded from. */
public enum LoadedFrom {
MEMORY(Color.GREEN),
DISK(Color.BLUE),
NETWORK(Color.RED);

final int debugColor;

private LoadedFrom(int debugColor) {
this.debugColor = debugColor;
}
}
}


4 retry说明

1 在hunt()出错时如NetworkRequestHandler.ContentLengthException和IOException

会进行dispatcher.dispatchRetry(this);

2 dispatcher.performRetry(hunter);

boolean shouldRetry(boolean airplaneMode, NetworkInfo info) {//重试的次数判断
boolean hasRetries = retryCount > 0;
if (!hasRetries) {
return false;
}
retryCount--;
return requestHandler.shouldRetry(airplaneMode, info);
}

void performRetry(PPBitmapHunter hunter) {
if (hunter.isCancelled()) return;
if (service.isShutdown()) {// 确定线程池OK
performError(hunter, false);//否则回调告诉error
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);//回调告知error
if (willReplay) {
markForReplay(hunter);//保存到failedActions,当收到网络通知并连接成功时会重新处理failedActions
}
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));
}
//noinspection ThrowableResultOfMethodCallIgnored
if (hunter.getException() instanceof AANetworkRequestHandler.ContentLengthException) {
hunter.networkPolicy |= NetworkPolicy.NO_CACHE.index;
}
hunter.future = service.submit(hunter);//提交这个hunter,重试
return;
}
performError(hunter, supportsReplay);//回调告知error
if (supportsReplay) {
markForReplay(hunter);
}
}


另:

batch(hunter)是在performError和performComplete中调用的,之后执行如下

void performBatchComplete() {
List<PPBitmapHunter> copy = new ArrayList<PPBitmapHunter>(batch);
batch.clear();
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
logBatch(copy);
}


每次可能同时有多个图片获取成功,因此利用batch去批处理获取成功的hunter,回调到主线程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  picasso