Picasso是目前android最流行的图片加载框架之一,此篇的内容就是简略的介绍一下Picasso的实现
结构
简单整理一下各个类直接的关系,大体就是这个样子
其中的核心类是
Picasso RequestCreator RequestHandler Action Dispatcher
其中Picasso以单例实现,外部通过load方法创建并获取一个RequestCreator 实例,后续逻辑控制在这个RequestCreator
实例中。此时,RequestCreator 的职责已经超过其命名,更像是这次图片获取任务的Manager或者Holder。
每个ImageView在into之后,会对应生成一个DeferredRequestCreator,DeferredRequestCreator 会持有一个RequestCreator,并且监控View的onPreDraw,在此时开始图片加载。
RequestCreator内部创建特定Action经Picasso交由Dispatcher执行操作BitmapHunter。
Picasso创建时会一同创建所有可能需要的RequestHandler,创建时通过入参可添加,并在创建BitmapHunter时选择合适的RequestHandler使用。
BitmapHunter本身是一个Runnable,其中主要方法是hunt。
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");
}
return bitmap;
}
}
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) {
Source source = result.getSource();
try {
bitmap = decodeStream(source, data);
} finally {
try {
//noinspection ConstantConditions If bitmap is null then source is guranteed non-null.
source.close();
} catch (IOException ignored) {
}
}
}
}
if (bitmap != null) {
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId());
}
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;
}
static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
Action action) {
Request request = action.getRequest();
List 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)) {
return new BitmapHunter(picasso, dispatcher, cache, stats, action, requestHandler);
}
}
return new BitmapHunter(picasso, dispatcher, cache, stats, action, ERRORING_HANDLER);
}
static Bitmap decodeStream(Source source, Request request) throws IOException {
BufferedSource bufferedSource = Okio.buffer(source);
boolean isWebPFile = Utils.isWebPFile(bufferedSource);
boolean isPurgeable = request.purgeable && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP;
BitmapFactory.Options options = RequestHandler.createBitmapOptions(request);
boolean calculateSize = RequestHandler.requiresInSampleSize(options);
// 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 = bufferedSource.readByteArray();
if (calculateSize) {
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
RequestHandler.calculateInSampleSize(request.targetWidth, request.targetHeight, options,
request);
}
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
} else {
InputStream stream = bufferedSource.inputStream();
if (calculateSize) {
// TODO use an InputStream that buffers with Okio...
MarkableInputStream markStream = new MarkableInputStream(stream);
stream = markStream;
markStream.allowMarksToExpire(false);
long mark = markStream.savePosition(1024);
BitmapFactory.decodeStream(stream, null, options);
RequestHandler.calculateInSampleSize(request.targetWidth, request.targetHeight, options,
request);
markStream.reset(mark);
markStream.allowMarksToExpire(true);
}
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;
}
}
可以看到其中decode,获取result等操作都会使用创建时置入RequestHandler进行处理。
以上就是Picasso的大体结构及核心逻辑