picasso不完全解析

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);

OK,说的也不少了,关于picasso缓存方面就到这里,下面我们来研究下,Picasso图片压缩的技术

致谢:http://blog.csdn.net/chdjj/article/details/49964901