picasso不完全解析
如题,今天我要做的是对picasso进行不完全解析,切入点就那么几点:
1.如何初始化
2.怎么做的联网请求
3.如何做的图片压缩
4.如何做的内存与本地缓存
/**
* The global {@link Picasso} instance.
* <p>
* This instance is automatically initialized with defaults that are suitable to most
* implementations.
* <ul>
* <li>LRU memory cache of 15% the available application RAM</li>
* <li>Disk cache of 2% storage space up to 50MB but no less than 5MB. (Note: this is only
* available on API 14+ <em>or</em> if you are using a standalone library that provides a disk
* cache on all API levels like OkHttp)</li>
* <li>Three download threads for disk and network access.</li>
* </ul>
* <p>
* If these settings do not meet the requirements of your application you can construct your own
* with full control over the configuration by using {@link Picasso.Builder} to create a
* {@link Picasso} instance. You can either use this directly or by setting it as the global
* instance with {@link #setSingletonInstance}.
*/
public static Picasso with() {
if (singleton == null) {
synchronized (Picasso.class) {
if (singleton == null) {
if (PicassoProvider.context == null) {
throw new IllegalStateException("context == null");
}
singleton = new Builder(PicassoProvider.context).build();
}
}
}
return singleton;
}
喏,这就是picasso 的初始化代码,请注意,下面的代码不重要,其中的注释很重要,英语好的同学应该一眼就看懂了.
现在我来解释一下:
picasso 的with方法,其实是picasso的初始化方法,他只是做了一些picasso 的基本设置,定制了一下picasso的配置参数,如果你对picasso有自己特殊的定义的话,可以通过picasso.Builder去做自己的自定义。
那么picasso默认的定义是怎样的呢?
1、指定了内存缓存的空间大小:为应用最大空间的15%,应用空间大概100多兆,那么给他内存分配的空间大概就是15~30兆左右了,这样其实能够满足一般的需求了。
2、指定了本地缓存空间,注释是说是本地sd卡空间的2%,但是sd卡现在越做越大,从最小的16G到最大的256G,2%其实也是很大的,所以他又做了一个限制,即2m~50m之间,ok,这样挺好的,能够满足一般的应用了。
我们可以通过Picasso.Builder()中的 memoryCache方法给Builder传入Cache对象就可以改变内存缓存的控制器,默认Picasso采用的是LruCache,即google官方推荐的内存算法机制
那么,我们第一个研究题目是 picasso怎么做的缓存
memoryCache方法:
/** Specify the memory cache used for the most recent images. */
public Builder memoryCache(@NonNull Cache memoryCache) {
if (memoryCache == null) {
throw new IllegalArgumentException("Memory cache must not be null.");
}
if (this.cache != null) {
throw new IllegalStateException("Memory cache already set.");
}
this.cache = memoryCache;
return this;
}
默认传入的cache对象:
/** Create a cache using an appropriate portion of the available RAM as the maximum size. */
public LruCache(@NonNull Context context) {
this(Utils.calculateMemoryCacheSize(context));
}
-----------------------------------------------------------------------------------------
static int calculateMemoryCacheSize(Context context) {
ActivityManager am = getService(context, ACTIVITY_SERVICE);
boolean largeHeap = (context.getApplicationInfo().flags & FLAG_LARGE_HEAP) != 0;
int memoryClass = largeHeap ? am.getLargeMemoryClass() : am.getMemoryClass();
// Target ~15% of the available heap.
return (int) (1024L * 1024L * memoryClass / 7);
}
默认是对应用内存的1/7,算一下差不多是15%对吧,记住,确切的是1/7然后做的取整。
再来看看单独设置的硬盘缓存大小:
/** Specify the {@link Downloader} that will be used for downloading images. */
public Builder downloader(@NonNull Downloader downloader) {
if (downloader == null) {
throw new IllegalArgumentException("Downloader must not be null.");
}
if (this.downloader != null) {
throw new IllegalStateException("Downloader already set.");
}
this.downloader = downloader;
return this;
}
这里他要传的downloader是picasso自己定义的一个接口,但是他还提供了一个自己的downloader,即:OkHttp3Downloader
果然,大公司写框架都是一套一套的,都是用的自己的,对自己的代码绝对自信。不知道J神去了google,square公司会怎样。
接着,那么默认传入的downloader是谁呢?
/**
* Create new downloader that uses OkHttp. This will install an image cache into your application
* cache directory.
*/
public OkHttp3Downloader(final Context context) {
this(Utils.createDefaultCacheDir(context));
}
---
static File createDefaultCacheDir(Context context) {
File cache = new File(context.getApplicationContext().getCacheDir(), PICASSO_CACHE);
if (!cache.exists()) {
//noinspection ResultOfMethodCallIgnored
cache.mkdirs();
}
return cache;
}
---
private static final String PICASSO_CACHE = "picasso-cache";
但是,这个跟上文说的不一样呀,不是说指定的空间是sd卡的2%吗,现在怎么直接进入应用的空间了,应用的空间可是存储在ram当中的呀。。。。
对,没错,默认picasso就是这么设置的,如果不想这样的话,只能自己定义硬盘的存储目录了,当然,picasso也给我们定制好了
/**
* Create new downloader that uses OkHttp. This will install an image cache into the specified
* directory.
*
* @param cacheDir The directory in which the cache should be stored
*/
public OkHttp3Downloader(final File cacheDir) {
this(cacheDir, Utils.calculateDiskCacheSize(cacheDir));
}
你只需要传入一个目录就好了,里面的空间大小算法就是根据上边说的2%定义好的
@TargetApi(JELLY_BEAN_MR2)
static long calculateDiskCacheSize(File dir) {
long size = MIN_DISK_CACHE_SIZE;
try {
StatFs statFs = new StatFs(dir.getAbsolutePath());
//noinspection deprecation
long blockCount =
SDK_INT < JELLY_BEAN_MR2 ? (long) statFs.getBlockCount() : statFs.getBlockCountLong();
//noinspection deprecation
long blockSize =
SDK_INT < JELLY_BEAN_MR2 ? (long) statFs.getBlockSize() : statFs.getBlockSizeLong();
long available = blockCount * blockSize;
// Target 2% of the total space.
size = available / 50;
} catch (IllegalArgumentException ignored) {
}
// Bound inside min/max size for disk cache.
return Math.max(Math.min(size, MAX_DISK_CACHE_SIZE), MIN_DISK_CACHE_SIZE);
}
OK,Picasso的缓存基本上就是上面的部分了,默认picasso是为我们提供了缓存的,当然我们可以选择不用缓存,那么picasso也为我们提供了跳过缓存的方法:
我们都知道,picasso.with()方法返回的就是我们Picasso的实例对象,而picasso.with().load()方法实际上返回的是是一个requestCreator对象,而into()方法则将 request请求真正的创建出来。解决跳过缓存的逻辑就在RequestCreate中。
/**
* Specifies the {@link MemoryPolicy} to use for this request. You may specify additional policy
* options using the varargs parameter.
*/
public RequestCreator memoryPolicy(@NonNull MemoryPolicy policy,
@NonNull MemoryPolicy... additional) {
if (policy == null) {
throw new IllegalArgumentException("Memory policy cannot be null.");
}
this.memoryPolicy |= policy.index;
if (additional == null) {
throw new IllegalArgumentException("Memory policy cannot be null.");
}
if (additional.length > 0) {
for (MemoryPolicy memoryPolicy : additional) {
if (memoryPolicy == null) {
throw new IllegalArgumentException("Memory policy cannot be null.");
}
this.memoryPolicy |= memoryPolicy.index;
}
}
return this;
}
通过以上RequestCreator给我们提供的方法,我们就能够知道我们只需要在load()方法之后添加一个memoryPilicy()方法即可。里面传入一个memory的策略就行了:
那么策略有两个
/ Skips memory cache lookup when processing a request. */
NO_CACHE(1 << 0),
/
- Skips storing the final result into memory cache. Useful for one-off requests
- to avoid evicting other bitmaps from the cache.
*/
NO_STORE(1 << 1);
那么,我们就这样使用好了Picasso.with(getContext()).load(imageUrl).memoryPolicy(MemoryPolicy.NO_CACHE).into(image);