Picasso源码分析

Picasso介绍

https://github.com/square/picasso

Picasso是Android开发中常用的几大图片加载库之一,除此之外常用的还有UIL、Glide、Fresco等。
目前UIL作者已经不再维护,Glide源码比较复杂,Fresco涉及c语言层面。相比之下Picasso写得比较简洁、规范,更好入手分析。

通过分析Picasso源码来对Android的图片加载有更深入的理解。

目前最新版本为2.71828(奇葩的版本号),本文基于此分析。

最新的使用方式为:

1
PicassoProvider.get().load("url").into(imageview)

下面就根据这个调用流程来分析其源码。

图示

Picasso的get方法

此前Picasso包括Glide的调用方式都需要通过with(context)方法来传入context,最新版本通过一个get方法即可实现。

项目中单独提供一个picasso-provider库工程实现此方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public final class PicassoProvider {
@SuppressLint("StaticFieldLeak")
private static volatile Picasso instance;

@Initializer
public static Picasso get() {
if (instance == null) {
synchronized (PicassoProvider.class) {
if (instance == null) {
Context autoContext = PicassoContentProvider.context;
if (autoContext == null) {
throw new NullPointerException("context == null");
}
instance = new Picasso.Builder(autoContext).build();
}
}
}
return instance;
}
...
}

此处使用双重校验锁来实现Picasso类单例。

context的获取通过PicassoContentProvider类实现:

1
2
3
4
5
6
7
8
9
10
public final class PicassoContentProvider extends ContentProvider {
@SuppressLint("StaticFieldLeak")
@Nullable static Context context;

@Override public boolean onCreate() {
context = getContext();
return true;
}
...
}

此类在AndroidManifest中注册,因此在App启动的时候,系统就会自动回调PicassoContentProvider 的onCreate方法,因此也就自动获取到了Context。

Picasso的创建

Picasso通过Builder模式创建实例,通过以下这行代码获取实例。

1
instance = new Picasso.Builder(autoContext).build();

Builder类构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Builder(Picasso picasso) {
context = picasso.context;
// OkHttp的Call工厂,使用OkHttp处理网络请求
callFactory = picasso.callFactory;
// 请求分发服务
service = picasso.dispatcher.service;
// 缓存处理类
cache = picasso.cache;
// 回调监听
listener = picasso.listener;
// 变换器,List<RequestTransformers>
requestTransformers.addAll(picasso.requestTransformers);
// 计算请求处理器数量,List<RequestHandler>后续分析
int numRequestHandlers = picasso.requestHandlers.size();
requestHandlers.addAll(picasso.requestHandlers.subList(2, numRequestHandlers - 6));

defaultBitmapConfig = picasso.defaultBitmapConfig;
indicatorsEnabled = picasso.indicatorsEnabled;
loggingEnabled = picasso.loggingEnabled;
}

build方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public Picasso build() {
Context context = this.context;
// 配置OkHttp3 Cache和Factory
okhttp3.Cache unsharedCache = null;
if (callFactory == null) {
File cacheDir = createDefaultCacheDir(context);
long maxSize = calculateDiskCacheSize(cacheDir);
unsharedCache = new okhttp3.Cache(cacheDir, maxSize);
callFactory = new OkHttpClient.Builder()
.cache(unsharedCache)
.build();
}
// 配置Picasso的Cache,使用LRU最近最少使用方式缓存
if (cache == null) {
cache = new PlatformLruCache(Utils.calculateMemoryCacheSize(context));
}
// 默认使用PicassoExecutorService线程池,用于后续Bitmap的获取
if (service == null) {
service = new PicassoExecutorService();
}
// 统计信息类,统计缓存命中,图片下载数等数据
Stats stats = new Stats(cache);
// 请求分发,HANDLER在主线程处理事件,用于将获取到的Bitmap显示
Dispatcher dispatcher = new Dispatcher(context, service, HANDLER, cache, stats);
// 返回Picasso实例
return new Picasso(context, dispatcher, callFactory, unsharedCache, cache, listener,
requestTransformers, requestHandlers, stats, defaultBitmapConfig, indicatorsEnabled,
loggingEnabled);
}

Picasso构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Picasso(...) {
...
// Picasso内置一个List<RequestTransformer>用于处理请求变换
this.requestTransformers = Collections.unmodifiableList(new ArrayList<>(
...
// Picasso 默认包含8个内置 RequestHandler 分别用来处理8种不同类型的请求
int builtInHandlers = 8;
...

// 可添加自定义的RequestHandler
List<RequestHandler> allRequestHandlers = new ArrayList<>(builtInHandlers + extraCount);
// ResourceRequestHandler,用于处理.xml资源文件
allRequestHandlers.add(ResourceDrawableRequestHandler.create(context));

// ResourceRequestHandler,用于处理Res资源文件
allRequestHandlers.add(new ResourceRequestHandler(context));

allRequestHandlers.addAll(extraRequestHandlers);

// ContactsPhotoRequestHandler,用于处理手机联系人图片
allRequestHandlers.add(new ContactsPhotoRequestHandler(context));

// MediaStoreRequestHandler,用于处理content://media/开头的URI
allRequestHandlers.add(new MediaStoreRequestHandler(context));

// ContentStreamRequestHandler,用于处理scheme为content的URI
allRequestHandlers.add(new ContentStreamRequestHandler(context));

// AssetRequestHandler,用于处理file:///android_asset/开头的URI
allRequestHandlers.add(new AssetRequestHandler(context));

// FileRequestHandler,用于处理scheme为file的URI
allRequestHandlers.add(new FileRequestHandler(context));

// NetworkRequestHandler,用于处理http或https图片url
allRequestHandlers.add(new NetworkRequestHandler(callFactory, stats));

// 返回一个不能进行修改操作的List实例,防止requestHandlers被修改
requestHandlers = Collections.unmodifiableList(allRequestHandlers);
...
}

Picasso创建分析完毕。

Picasso的load方法

load方法对应不同的重载方法:包括int、String、Object、Uri等,以Uri为例:

1
2
3
public RequestCreator load(@Nullable Uri uri) {
return new RequestCreator(this, uri, 0);
}

最终创建并返回一个RequestCreator实例。

1
2
3
4
5
6
7
RequestCreator(Picasso picasso, @Nullable Uri uri, int resourceId) {
...
// 持有Picasso实例
this.picasso = picasso;
// 通过Builder创建Request
this.data = new Request.Builder(uri, resourceId, picasso.defaultBitmapConfig);
}

RequestCreator核心就是创建Request.Builder,即data实例。

RequestCreator创建完成后,内部还包含placeholder、error、fit等方法,可继续链式调用,这里主要分析主流程,不详细赘述。

RequestCreator的into方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public void into(@NonNull ImageView target, @Nullable Callback callback) {
...
// data即前面的Request.Builder实例
// 如果data中没有图片(例如传入的path为null)
// 直接对该target取消请求,并设置占位图如果有设置placeholder
if (!data.hasImage()) {
picasso.cancelRequest(target);
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}
return;
}

...
// 创建请求
Request request = createRequest(started);
// 如果当前的memoryPolicy允许从缓存中读取图片
// 从Cache中获取 requestKey 对应的Bitmap,如果该Bitmap存在
// 则取消当前请求,直接为target设置该Bitmap
if (shouldReadFromMemoryCache(request.memoryPolicy)) {
Bitmap bitmap = picasso.quickMemoryCacheCheck(request.key);
if (bitmap != null) {
picasso.cancelRequest(target);
RequestHandler.Result result = new RequestHandler.Result(bitmap, MEMORY);
setResult(target, picasso.context, result, noFade, picasso.indicatorsEnabled);
if (picasso.loggingEnabled) {
log(OWNER_MAIN, VERB_COMPLETED, request.plainId(), "from " + MEMORY);
}
if (callback != null) {
callback.onSuccess();
}
return;
}
}

// 前面缓存中没有查找到图片,从这里开始请求
// 先设置 placeholder 如果有配置的话
if (setPlaceholder) {
setPlaceholder(target, getPlaceholderDrawable());
}

// 创建ImageViewAction,主要将获取的Bitmap加载到ImageView中
Target<ImageView> wrapper = new Target<>(target, errorResId, errorDrawable, noFade);
Action action = new ImageViewAction(picasso, wrapper, request, callback);
// 加入异步请求队列处理
picasso.enqueueAndSubmit(action);
}

createRequest创建Request实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private Request createRequest(long started) {
int id = nextId.getAndIncrement();

// 创建Request
Request request = data.build();
request.id = id;
request.started = started;

boolean loggingEnabled = picasso.loggingEnabled;
if (loggingEnabled) {
log(OWNER_MAIN, VERB_CREATED, request.plainId(), request.toString());
}

// 如果有RequestTransformer,则逐一处理
Request transformed = picasso.transformRequest(request);
if (transformed != request) {
// If the request was changed, copy over the id and timestamp from the original.
transformed.id = id;
transformed.started = started;

if (loggingEnabled) {
log(OWNER_MAIN, VERB_CHANGED, transformed.logId(), "into " + transformed);
}
}

// 返回Request
return transformed;
}

上述主要分析了PicassoProvider.get().load(“url”).into(imageview)整体流程。

Dispatcher处理请求流程

前面分析into方法的最后,图片以Action的形式加入Picasso请求:

1
2
3
4
5
picasso.enqueueAndSubmit(action)

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

请求加入Dispatcher中,然后放到Handler进行处理。

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

Dispatcher核心是DispatcherThread、DispatcherHandler、PicassoExecutorService。

DispatcherThread是一个HandlerThread,HandlerThread有自己的内部Looper对象,将Message发送给DispatcherHandler在handleMessage进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
private static class DispatcherHandler extends Handler {
private final Dispatcher dispatcher;

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;
}
// hunter完成
case HUNTER_COMPLETE: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performComplete(hunter);
break;
}
// hunter重试
case HUNTER_RETRY: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performRetry(hunter);
break;
}
// hunter解码失败
case HUNTER_DECODE_FAILED: {
BitmapHunter hunter = (BitmapHunter) msg.obj;
dispatcher.performError(hunter);
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);
}
});
}
}
}

再来看看Dispathcer的perormSubmit方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
void performSubmit(Action action, boolean dismissFailed) {
// 前面是做一些必要的判断处理
...

// 获取Action的Hunter
hunter = forRequest(action.getPicasso(), this, cache, stats, action);
// 将Hunter加入线程池
hunter.future = service.submit(hunter);
// 存入hunterMap中
hunterMap.put(action.getKey(), hunter);

...
}

service即PicassoExecutorService,是Picasso实现基于优先级队列PriorityBlockingQueue的线程池,继承于ThreadPoolExecutor,内部有一个FutureTask实现类PicassoFutureTask。

PicassoFutureTask通过compareTo方法比较请求的优先级,具体实现在其内部持有的BitmapHunter内部。

BitmapHunter是Runnable子类,具体作用就是“狩猎”bitmap,返回一个持有bitmap的Result。

service.submit(hunter)即是将FutureTask提交到线程池处理,返回一个Future,此处之所以用FutureTask,是用于监听hunter是否执行完毕且可以cancel执行。

BitmapHunter其核心是run里的hunt方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
Result hunt() throws IOException {
// 缓存命中则直接获取Result返回
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);
}
}

...

// RequestHandler即最开始提的8种请求处理,根据图片来源的不同进行处理
final CountDownLatch latch = new CountDownLatch(1);
try {
requestHandler.load(picasso, data, new RequestHandler.Callback() {
@Override public void onSuccess(@Nullable Result result) {
resultReference.set(result);
latch.countDown();
}

@Override public void onError(@NonNull Throwable t) {
exceptionReference.set(t);
latch.countDown();
}
});

latch.await();
} catch (InterruptedException ie) {
InterruptedIOException interruptedIoException = new InterruptedIOException();
interruptedIoException.initCause(ie);
throw interruptedIoException;
}

...

Result result = resultReference.get();
Bitmap bitmap = result.getBitmap();
if (bitmap != null) {
if (picasso.loggingEnabled) {
log(OWNER_HUNTER, VERB_DECODED, data.logId());
}
// 解码bitmap
stats.dispatchBitmapDecoded(bitmap);

// 做Transformation变换处理
List<Transformation> transformations = new ArrayList<>(data.transformations.size() + 1);
if (data.needsMatrixTransform() || result.getExifRotation() != 0) {
transformations.add(new MatrixTransformation(data));
}
transformations.addAll(data.transformations);

result = applyTransformations(picasso, data, transformations, result);
bitmap = result.getBitmap();
if (bitmap != null) {
stats.dispatchBitmapTransformed(bitmap);
}

// 返回Result
return result;
}

run方法再将处理的结果发送回Dispathcer,例如dispatchComplete和dispatchFailed。

Dispathcer里还维护了一个主线程Handler,mainThreadHandler,在Picasso类实现传入。

前面处理的结果最终会通过一个deliver方法传回mainThreadHandler,通过回调监听返回listener返回给Picasso使用方,即App。

至此,Picasso主要流程分析完毕。

0%