彻底掌握如何有效处理高清大图(如何更高效更快速的加载图片)

彻底掌握如何有效处理高清大图:Android-Universal-Image-Loader框架解析(一)基本使用
彻底掌握如何有效处理高清大图:Android-Universal-Image-Loader框架解析(二)缓存
彻底掌握如何有效处理高清大图:Android-Universal-Image-Loader框架解析(三)下载模块,解码模块和显示模块
??在之前的框架中,当硬盘中有图片缓存的时候,便会通过预处理硬盘中的图片并加载这些图片;
【彻底掌握如何有效处理高清大图(如何更高效更快速的加载图片)】这里我们要解决的问题是: 如何更高效更快速的从本地文件中加载一张图片;
?? 首先我们从性能上对比下效果
?? 测试准备:
1.4M大小的JPEG图片,循环加载1000次;
?? 测试结果对比:
从普通文件系统加载需要 290505 ms
从缓存文件系统加载需要 3819 ms
?? 然后我们概览下架构
彻底掌握如何有效处理高清大图(如何更高效更快速的加载图片)
文章图片

?? 为了理解这个总体架构,我们首先简单说明下Blob, Blob他是一个二进制大对象,以字节数组的方式存储,可以理解为是一个可以存储很多二进制对象的容器,适用于非文本数据,图片、视频、pdf文件、MP3文件等等
?? 在这个结构中,ImageCacheService并非一个Service, 其实一个普通的java类,内部维护这BlobCache对象,这个类有如下几个作用

  1. 根据给定的图片路径获得图片的缓存数据
  2. 将对应路径的图片放到缓存当中
?? 在这个结构中,Blob Cache代码缓存在磁盘上图片,其会将64个字节映射到字节数组当中; 其主要数据结构如下:
  1. 一个index文件(图片索引文件): imgchche.idx
  2. 两个数据文件(存放缩略图内容): imgcache.0 imgcache.1
?? 为什么会有这样的数据结构? 这就要说下 BlobCache算法了,BlobCache算法和LruCache算法都是图片缓存算法,在BlobCache算法中imgcache.0和imgcache.1文件一个是活动的,一个是不活动的,之所以说一个活动一个不活动,是因为文件有一定的存储大小,当imgcache.0的存储到达一定界限的时候,就会使用imgcache.1文件;
?? 在这样的文件缓存设计中,其核心步骤有两个
  1. 将图片保存到缓存文件中
  2. 从缓存文件中取出图片
?? 先大致看下将图片保存到缓存文件的过程
彻底掌握如何有效处理高清大图(如何更高效更快速的加载图片)
文章图片

?? 再大致看下从缓存文件中取出图片的过程
彻底掌握如何有效处理高清大图(如何更高效更快速的加载图片)
文章图片

?? 到这边似乎和普通的图片缓存框架没啥区别,那我们就得着重看下BlobCache算法了。BlobCache的算法的好处就在于他设计了一个非常好的文件架构用来快速找到对应的图片,先逐一看下BlobCache算法的索引文件和内容文件的数据结构
彻底掌握如何有效处理高清大图(如何更高效更快速的加载图片)
文章图片

??index file是寻找图片数据的入口,他会根据key寻找到对应的Content File中的Blob;
index file文件分为头信息和index部分,其中index部分就是包含各个图片的索引key
??content file分为头信息和Blob两个部分,其中Blog中的payload字段就表示一张张具体的图片内容
??大体的流程看过之后,我们在来细看几个关键的地方:
  1. 如何根据文件路径创建索引key
  2. 如何映射key和blob
??如何根据文件路径创建索引key
将图片的path,timemodified,具体的图片数据转成的byte[],在将其生成一个64位的CRC编码,来作为key。
public static final crc64Long(byte[] buffer) { long crc = INITIALCRC for (int k = 0 , n = buffer.length ; k < n, ++k) { crc = sCrcTable[(((int)crc) ^ buffer[k]) & 0xff] ^ (crc >> 8); } }

??如何映射key和blob
private boolean lookupInteral(long key, int hashStart) { int slot = (int) (key % mMaxEntries); if (slot < 0) slot += mMaxEntries; int slotBegin = slot; while (true) { int offset = hashStart +slot * 12; long candidataKey = mIndexBuffer.getLong(offset); int candidateOffset = mIndexBuffer.getLong(offset + 8); if (candidateOffset == 0) { mSlotOffset = offset; return false } else if (candidataKey == key){ mSlotOffset = offset; mFileOffset = candidateOffset; return true; } else { if (++ slot >= mMaxEntries) { slot = 0; } if (slot == slotBegin) { mIndexBuffer.putInt(hashStart + slot * 12 + 8 , 0); } } } }

    推荐阅读