Picasso源码学习(二)

继上一篇文章简单分析了一下Picasso的图片加载流程,这次就接着小小地研究一把图片加载中最为重要的一个部分——缓存机制。当然,这段源码阅读过程自然是以上一篇文章中Picasso请求加载流程为基础的。

源码阅读

从上一篇的内容来看,在图片加载的过程中调用了一个方法。

1
Picasso.quickMemoryCacheCheck(target, requestKey);

这个方法从名字里也可以看出来它的作用是从内存中检查所需的Bitmap资源是否已经存在,如果存在则从缓存中取出来,所以我们首先来看看这个方法干了什么。

1
2
3
4
5
6
7
8
9
10
11
12
Bitmap quickMemoryCacheCheck(Object target, String key) {
//通过键key作为索引来从缓存中查找Bitmap对象,如果没有则返回null
Bitmap cached = cache.get(key);
cancelExistingRequest(target, key);
if (cached != null) {
stats.cacheHit();
}
return cached;
}

这里关心的主要是cache.get()的调用,这里的cache是一个Cache对象,Cache是一个被设计来专门用于缓存的接口,不是很复杂,在看看cache的具体类型之前,先来看看这个接口。

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
public interface Cache {
//根据特定的键来从缓存中获取图片资源,如果缓存中没有则返回null
Bitmap get(String key);
//将一个String对象和一个Bitmap对象以键值对的形式存入缓存中
void set(String key, Bitmap bitmap);
//返回当前缓存中的内容大小
int size();
//返回缓存所能存放的最大数据量
int maxSize();
//一个空缓存对象,表示没有存储任何内容
Cache NONE = new Cache() {
@Override public Bitmap get(String key) {
return null;
}
@Override public void set(String key, Bitmap bitmap) {
// Ignore.
}
@Override public int size() {
return 0;
}
@Override public int maxSize() {
return 0;
}
};
}

对于每一个方法这里都注释了,也极易明白。再回过头来看看cache的创建过程来看看它的具体类型。

1
2
3
memoryCache = new LruCache(context);
new Picasso(context, loader, service, memoryCache, stats);

这里的memoryCache的类型便是Cache类型,而这个创建的代码就在是在Picasso.Builder的构造函数中,最后被传入Picasso的构造函数,赋值给cache。从这里可以看出来它的具体类型是LruCache。从名字中不难猜出,它实际上是通过使用LRU算法实现的缓存存取过程的。这里的LruCache并不是我们熟知的Androidsupport-v4包中的类LruCache,但其实现原理都是一摸一样的,都是采用LRU算法将所需缓存的数据存进一个LinkedHashMap中。

上面所提到的便是Picasso的内存缓存机制,那么它的磁盘缓存是通过什么方法实现的呢。其实Picasso的磁盘缓存是通过OkHttp的缓存功能来实现的。这里我们回到Loader类中的createDefaultLoader方法。

1
2
3
4
5
6
7
8
static Loader createDefaultLoader(Context context) {
try {
Class.forName("com.squareup.okhttp.OkHttpClient");
return OkHttpLoaderCreator.create(context);
} catch (ClassNotFoundException e) {
return new UrlConnectionLoader(context);
}
}

这个方法的执行过程便是在发现内存缓存中没有所想要的内容时开始通过网络发起请求的时候所发生的。这里先前介绍过实际请求调用的便是其中OkHttpLoader中的loader()方法。

1
2
3
4
5
6
7
8
9
10
11
@Override public Response load(String url, boolean localCacheOnly) throws IOException {
HttpURLConnection connection = client.open(new URL(url));
connection.setUseCaches(true);
if (localCacheOnly) {
connection.setRequestProperty("Cache-Control", "only-if-cached");
}
boolean fromCache = parseResponseSourceHeader(connection.getHeaderField(RESPONSE_SOURCE));
return new Response(connection.getInputStream(), fromCache);
}

从这里我们便可以一眼看出来,在发起请求的时候,所设置的属性便是对请求内容进行缓存,也就是说如果OkHttp的缓存中已经有了所需的图片资源,那就直接获取,如果没有则继续请求。

通过我们的分析算是证实了Picasso的磁盘缓存机制是通过OkHttp来实现的。但是,Square公司早已推了OkHttp3,但即使是checkout到最新版本的Picasso也并没有从中发现OkHttp3到影子,这就带来一个问题,实际使用Picasso到时候就会由于出现没有使用OkHttp的情况而出现无法使用磁盘缓存的问题。这里便向想要结局这个问题的同学推荐一个库picasso2-okhttp3-downloader,这时Jake大神为这个问题所专门写的,其中的实现机制其实很简单,和Picasso内的OkHttpLoader如出一辙,一看便知。

最后

这部分的不长,主要就是我自己查看Picasso缓存机制的一个简单的流程记录,内容也很简单,同时又不可或缺所以就单独拿出来了,还是恨通俗易懂的。