三级缓存

1. Bitmap缓存

Bitmap缓存存储Bitmap对象,这些Bitmap对象可以立刻用来显示或者用于后处理

在5.0以下系统,Bitmap缓存位于ashmem,这样Bitmap对象的创建和释放将不会引发GC,更少的GC会使你的APP运行得更加流畅。

5.0及其以上系统,相比之下,内存管理有了很大改进,所以Bitmap缓存直接位于Java的heap上。

当应用在后台运行时,该内存会被清空

2. 未解码图片的内存缓存

这个缓存存储的是原始压缩格式的图片。从该缓存取到的图片在使用之前,需要先进行解码。

如果有调整大小,旋转,或者WebP编码转换工作需要完成,这些工作会在解码之前进行。

3. 磁盘缓存

和未解码的内存缓存相似,磁盘缓存存储的是未解码的原始压缩格式的图片,在使用之前同样需要经过解码等处理。

和磁盘缓存不一样,APP在后台时,内容是不会被清空的。即使关机也不会。用户可以随时用系统的设置菜单中进行清空缓存操作。

查找一个bitmap是否被缓存?

你可以使用ImagePipeline检查bitmap是否在缓存中。

1
2
3
ImagePipeline imagePipeline = Fresco.getImagePipeline();
Uri uri;
boolean inMemoryCache = imagePipeline.isInBitmapMemoryCache(uri);

查询内存缓存的操作是同步的, 不过查询缓存的操作是异步的。因为这个操作可以使用另一个线程操作。你可以这样使用:

1
2
3
4
5
6
7
8
9
10
11
12
DataSource<Boolean> inDiskCacheSource = imagePipeline.isInDiskCache(uri);
DataSubscriber<Boolean> subscriber = new BaseDataSubscriber<Boolean>() {
    @Override
    protected void onNewResultImpl(DataSource<Boolean> dataSource) {
      if (!dataSource.isFinished()) {
        return;
      }
      boolean isInCache = dataSource.getResult();
      // your code here
    }
  };
inDiskCacheSource.subscribe(subscriber, executor);

以上API假设你使用默认的CacheKeyFactory。如果你自定义CacheKeyFactory,你可能需要用把ImageRequest作为它的参数。

清除缓存中的一条url

ImagePipeline现有函数可以根据Uri删除缓存。

1
2
3
4
5
6
7
ImagePipeline imagePipeline = Fresco.getImagePipeline();
Uri uri;
imagePipeline.evictFromMemoryCache(uri);
imagePipeline.evictFromDiskCache(uri);

// combines above two lines
imagePipeline.evictFromCache(uri);

如同上面一样,evictFromDiskCache(Uri)假定你使用的是默认的CacheKeyFactory。如果你自定义,请使用evictFromDiskCache(ImageRequest)

清除缓存

1
2
3
4
5
6
ImagePipeline imagePipeline = Fresco.getImagePipeline();
imagePipeline.clearMemoryCaches();
imagePipeline.clearDiskCaches();

// combines above two lines
imagePipeline.clearCaches();

用一个还是两个磁盘缓存?

如果要使用2个缓存,在配置image pipeline 时调用 setMainDiskCacheConfigsetSmallImageDiskCacheConfig 方法即可。

大部分的应用有一个磁盘缓存就够了,但是在一些情况下,你可能需要两个缓存。比如你也许想把小文件放在一个缓存中,大文件放在另外一个文件中,这样小文件就不会因大文件的频繁变动而被从缓存中移除。

至于什么是小文件,这个由应用来区分,在创建image request, 设置 ImageType 即可:

1
2
ImageRequest request = ImageRequest.newBuilderWithSourceUri(uri)
    .setImageType(ImageType.SMALL)

如果你仅仅需要一个缓存,那么不调用setSmallImageDiskCacheConfig即可。Image pipeline 默认会使用同一个缓存,同时ImageType也会被忽略。

内存用量的缩减

配置Image pipeline 时,我们可以指定每个缓存最大的内存用量。但是有时我们可能会想缩小内存用量。比如应用中有其他数据需要占用内存,不得不把图片缓存清除或者减小 或者我们想检查看看手机是否已经内存不够了。

Fresco的缓存实现了DiskTrimmable 或者 MemoryTrimmable 接口。这两个接口负责从各自的缓存中移除内容。

在应用中,可以给Image pipeline配置上实现了DiskTrimmableRegistryMemoryTrimmableRegistry 接口的对象。

实现了这两个接口的对象要持有一个列表,这个列表以DiskTrimmableMemoryTrimmable 对象为元素。当应用程序判定当前状态下需要削减资源使用时,这些对象才会通知列表中的DiskTrimmableMemoryTrimmable 元素缩减各自的资源占用。

编辑和纠错