Picasso框架分析
https://github.com/square/picasso
implementation 'com.squareup.picasso:picasso:2.71828'
先来一张简图
核心组成
- Picasso:外观设计模式、门户
- Dispatcher:任务的分发调度者(运行在单独的线程中)
- PicassoExecutorService:线程池
- BitmapHunter:执行任务(模板设计模式)
- RequestHandler:任务的具体处理者(抽象类)
- Request:请求任务的封装
- Action:动作的封装
工作流程
Picasso picasso = new Picasso.Builder(getContext()).build();//这里可以使用单例模式包装一下
picasso.load(uri).into(imageView);
- 调用load()
2.创建一个RequestCreator - 调用into()
- 创建一个Request
- 创建一个对应的Action
- 通过Picasso提交给Dispatcher
- 创建BitmapHunter(创建时:查找到具体的处理者)
- 通过PicassoExecutorService去执行该BitmapHunter
具体的BitmapHunter执行任务
@Override public void run() {
try {
updateThreadName(data);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_EXECUTING, getLogIdsForHunter(this));
}
result = hunt(); // hunt()方法执行具体图片获取逻辑,下面都是异常处理
if (!result.hasBitmap()) {
dispatcher.dispatchFailed(this);
} else {
dispatcher.dispatchComplete(this);
}
} catch (NetworkRequestHandler.ResponseException e) {
if (!NetworkPolicy.isOfflineOnly(e.networkPolicy) || e.code != 504) {
exception = e;
}
dispatcher.dispatchFailed(this);
} catch (IOException e) {
exception = e;
dispatcher.dispatchRetry(this);
} catch (OutOfMemoryError e) {// 捕获了内存溢出的异常
Buffer buffer = new Buffer();
try {
stats.createSnapshot().dump(buffer);
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
exception = new RuntimeException(buffer.readUtf8(), e);
dispatcher.dispatchFailed(this);
} catch (Exception e) {
exception = e;
dispatcher.dispatchFailed(this);
} finally {
Thread.currentThread().setName(Utils.THREAD_IDLE_NAME);
}
}
Result hunt() throws IOException {
//-----------------------------------------------------------------------
// 一、先取内存缓存
if (shouldReadFromMemoryCache(data.memoryPolicy)) {
Bitmap bitmap = cache.get(key);
if (bitmap != null) {
stats.dispatchCacheHit();
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId(), "from cache");
}
return new Result(bitmap, MEMORY);
}
}
//-----------------------------------------------------------------------
if (retryCount == 0) {
data = data.newBuilder().networkPolicy(NetworkPolicy.OFFLINE).build();
}
//--------------------------------------------------------------------------------
// 二、通过具体的执行者去获取图片(如果是网络请求,使用的是OkHttp去下载)
final AtomicReference<Result> resultReference = new AtomicReference<>();
final AtomicReference<Throwable> exceptionReference = new AtomicReference<>();
final CountDownLatch latch = new CountDownLatch(1);// 1.线程同步工具
try {
requestHandler.load(picasso, data, new RequestHandler.Callback() {
@Override public void onSuccess(@Nullable Result result) {
resultReference.set(result);
latch.countDown();// 3.获取到图片后、结束等待
}
@Override public void onError(@NonNull Throwable t) {
exceptionReference.set(t);
latch.countDown();
}
});
latch.await();// 2.在此等待
} catch (InterruptedException ie) {
InterruptedIOException interruptedIoException = new InterruptedIOException();
interruptedIoException.initCause(ie);
throw interruptedIoException;
}
Throwable throwable = exceptionReference.get();
if (throwable != null) {
if (throwable instanceof IOException) {
throw (IOException) throwable;
}
if (throwable instanceof Error) {
throw (Error) throwable;
}
if (throwable instanceof RuntimeException) {
throw (RuntimeException) throwable;
}
throw new RuntimeException(throwable);
}
Result result = resultReference.get();
//--------------------------------------------------------------------------------
if (result.hasBitmap()) {
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId());
}
Bitmap bitmap = result.getBitmap();
stats.dispatchBitmapDecoded(bitmap);
// 三、图片处理
int exifOrientation = result.getExifRotation();
if (data.needsTransformation() || exifOrientation != 0) {
if (data.needsMatrixTransform() || exifOrientation != 0) {
bitmap = transformResult(data, bitmap, exifOrientation);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId());
}
}
result = new Result(bitmap, result.getLoadedFrom(), exifOrientation);
if (data.hasCustomTransformations()) {
result = applyCustomTransformations(data.transformations, result);
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_TRANSFORMED, data.logId(),
"from custom transformations");
}
}
}
if (result.hasBitmap()) {
stats.dispatchBitmapTransformed(result.getBitmap());
}
}
return result;
}
上面代码逻很简单、分为三步:(网络加载为例)
1.缓存中取
2.网络加载
3.图片处理
上面好像并没有看到磁盘缓存?
其实Picasso的磁盘缓存是使用了Okhttp的缓存,看代码
NetworkRequestHandler
@Override public void load(@NonNull Picasso picasso, @NonNull final Request request, @NonNull
final Callback callback) {
okhttp3.Request callRequest = createRequest(request);
// 使用Okhttp发起请求
callFactory.newCall(callRequest).enqueue(new okhttp3.Callback() {
@Override
public void onResponse(Call call, Response response) {
if (!response.isSuccessful()) {
callback.onError(new ResponseException(response.code(), request.networkPolicy));
return;
}
// 在此判断是磁盘缓存还是网络获取
Picasso.LoadedFrom loadedFrom = response.cacheResponse() == null ? NETWORK : DISK;
...
}
@Override public void onFailure(Call call, IOException e) {
callback.onError(e);
}
});
}
Picasso是一个轻量级的图片加载框架、代码量很少、使用起来也很方便,但是不支持GIF图片的加载。