Android Picasso

设计

Picasso 加载图片的流程

1
Picasso.get().load("").into(imageView);

Picasso.get()  创建一个 Picasso 单例,内部使用了建造者模式,单例模式和建造者模式。

load 方法返回一个 RequestCreator。

into 方法中中创建一个 request,request 作为创建 action 的参数之一,再 picasso.enqueueAndSubmit(action);

picasso submit 这个 action。

dispatcher.dispatchSubmit action,dispatcher 中的 handler 发送一个 message:

1
2
3
void dispatchSubmit(Action action) {
handler.sendMessage(handler.obtainMessage(REQUEST_SUBMIT, action));
}

dispatcher 内部有个 static 的 DispatcherHandler 类。收到 REQUEST_SUBMIT 类型的 message 会,dispatcher.performSubmit 。

尝试从 dispatcher 的 hunterMap 中根据 action 的 key 获取 BitmapHunter,将 hunter attach action。

上一步没获取到 hunter 时,dispatcher forRequest 创建 hunter,创建时将创建 picasso 时设置的 requestHander 设给 hunter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static BitmapHunter forRequest(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats,
Action action) {
Request request = action.getRequest();
List<RequestHandler> 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);
}

再:

1
hunter.future = service.submit(hunter);

BitmapHunter 实现了 Runnable,run 方法中 hunt 方法,从内存缓存中读,

读不到 requestHandler.load ,返回 RequestHandler.Result,

decodeStream

stats.dispatchBitmapDecoded

hunt 方法执行完返回 Bitmap,

1
2
3
4
5
6
7
result = hunt();

if (result == null) {
dispatcher.dispatchFailed(this);
} else {
dispatcher.dispatchComplete(this);
}
1
2
3
void dispatchComplete(BitmapHunter hunter) {
handler.sendMessage(handler.obtainMessage(HUNTER_COMPLETE, hunter));
}
1
2
3
4
5
case HUNTER_COMPLETE: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performComplete(hunter);
break;
}

写入内存缓存,再 dispatcher batch(),

1
2
3
4
5
6
7
8
9
10
11
12
private void batch(BitmapHunter hunter) {
if (hunter.isCancelled()) {
return;
}
if (hunter.result != null) {
hunter.result.prepareToDraw();
}
batch.add(hunter);
if (!handler.hasMessages(HUNTER_DELAY_NEXT_BATCH)) {
handler.sendEmptyMessageDelayed(HUNTER_DELAY_NEXT_BATCH, BATCH_DELAY);
}
}

200 ms 后发送 HUNTER_DELAY_NEXT_BATCH message,

1
2
3
4
5
6
void performBatchComplete() {
List<BitmapHunter> copy = new ArrayList<>(batch);
batch.clear();
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(HUNTER_BATCH_COMPLETE, copy));
logBatch(copy);
}

mainThreadHandler 是 picasso 中的 HANDLER,

1
complete
1
action.complete(result, from);

ImageViewAction

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override public void complete(Bitmap result, Picasso.LoadedFrom from) {
if (result == null) {
throw new AssertionError(
String.format("Attempted to complete action with no result!\n%s", this));
}

ImageView target = this.target.get();
if (target == null) {
return;
}

Context context = picasso.context;
boolean indicatorsEnabled = picasso.indicatorsEnabled;
PicassoDrawable.setBitmap(target, context, result, from, noFade, indicatorsEnabled);

if (callback != null) {
callback.onSuccess();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Create or update the drawable on the target {@link ImageView} to display the supplied bitmap
* image.
*/
static void setBitmap(ImageView target, Context context, Bitmap bitmap,
Picasso.LoadedFrom loadedFrom, boolean noFade, boolean debugging) {
Drawable placeholder = target.getDrawable();
if (placeholder instanceof Animatable) {
((Animatable) placeholder).stop();
}
PicassoDrawable drawable =
new PicassoDrawable(context, bitmap, placeholder, loadedFrom, noFade, debugging);
target.setImageDrawable(drawable);
}