Android图片框架Picasso LRU缓存详解(2)


static int calculateMemoryCacheSize(Context context) {
    ActivityManager am = getService(context, ACTIVITY_SERVICE);
    boolean largeHeap = (context.getApplicationInfo().flags & FLAG_LARGE_HEAP) != 0;
    int memoryClass = am.getMemoryClass();
    if (largeHeap && SDK_INT >= HONEYCOMB) {
      memoryClass = ActivityManagerHoneycomb.getLargeMemoryClass(am);
    }
    // Target ~15% of the available heap.
    return 1024 * 1024 * memoryClass / 7;
  } 这里是使用Context获得一个ActitityManager,然后用其获得获得一个以MB为单位的APP可占最大堆内存占用大小,然后使用这个最大APP占用的七分之一来做当前图片LRU缓存的最大可用大小,这个最大可用大小当然会随着手机配置的提高而变大,目前我这边测得的数据是:

红米note3: 19MB(3G内存)

Sony L50:22MB(3G内存)

红米2A:17MB(2G内存)
以经验来看,这样的内存分配并不大,经常出现在一个listView或者RecyclerView中,滑到底部后再滑回来,上面的元素的bitmap已经没有的情况,以RGB_8888为例,一个像素占用的大小为32字节,那么一个1920*1080的桌面背景图片所占得堆内存大小是1920*1080*32 = 63MB,对于这样图,LRU几乎是不会缓存的。

关于销毁指定LRU缓存:

手动销毁Picasso提供的默认LRU实现只能做到根据图片url进行销毁,而不能根据某个Activity或者Fragment进行销毁,如果想实现按照页面销毁的话,需要自己重写这个LruCache的实现。下面来看一下根据url进行销毁的源码:


@Override public final synchronized void clearKeyUri(String uri) {
    boolean sizeChanged = false;
    int uriLength = uri.length();
    for (Iterator<Map.Entry<String, Bitmap>> i = map.entrySet().iterator(); i.hasNext();) {
      Map.Entry<String, Bitmap> entry = i.next();
      String key = entry.getKey();
      Bitmap value = entry.getValue();
      int newlineIndex = key.indexOf(KEY_SEPARATOR);
      if (newlineIndex == uriLength && key.substring(0, newlineIndex).equals(uri)) {//加快寻找速度
        i.remove();//将相应的url所对bitmap移出LRU缓存
        size -= Utils.getBitmapBytes(value);//将当前总堆内存占用计数器减小被移出的bitmap大小
        sizeChanged = true;
      }
    }
    if (sizeChanged) {
      trimToSize(maxSize);//移出后执行以下内存检查,如果还是过大就继续销毁栈底的bitmap
    }
  }

我们在这里发现,Picasso默认的LRU缓存方案并不是我们需要的或者适合自己项目的方案,最好的方法是根据自己APP特点和业务需要重写LruCache,然后换掉Picasso默认的实现方案,方法如下:

Picasso.Builder builder = new Picasso.Builder(getContext());
        builder.memoryCache(new CustomLruCache());//设置自定义的缓存方案
        Picasso mPicasso = builder.build();//注意自定义Picasso实例要做成全局单例静态,否则缓存会失效同样方法可以自定义下载器,拦截器,线程池等等功能。


分析完这些实现,我们发现Picasso的强大之处并不在于针对某些应用场景提供完美的解决方案,而是它提供了一套完善的接口,让我们自由的根据自己APP的实际情况去自定义我们自己的策略,要想用好Picasso,光用的默认的方法是不行的,更重要的是了解图片下载、缓存、呈现的一系列需求并自定义自己的方案,然后借助Picasso来加载咱们自己的设定。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/4693d74a879bd76df46c8519554a94a2.html