当前位置: 首页 > news >正文

重庆网站建站推广wordpress模板中文

重庆网站建站推广,wordpress模板中文,2022最近十大的新闻热点,免费开发微信小程序的平台一、引言 在 Android 应用开发中#xff0c;图片加载和处理是常见且重要的功能。频繁的图片加载不仅会消耗大量的网络流量#xff0c;还会影响应用的性能和响应速度。因此#xff0c;有效的缓存机制对于提升图片加载效率和用户体验至关重要。Fresco 是 Facebook 开源的一款…一、引言 在 Android 应用开发中图片加载和处理是常见且重要的功能。频繁的图片加载不仅会消耗大量的网络流量还会影响应用的性能和响应速度。因此有效的缓存机制对于提升图片加载效率和用户体验至关重要。Fresco 是 Facebook 开源的一款强大的图片加载和显示库其缓存模块设计精巧能够高效地管理图片的内存缓存和磁盘缓存减少图片的重复加载从而显著提升应用的性能。 本文将深入剖析 Android Fresco 框架的缓存模块从源码级别详细分析其实现原理、缓存策略、数据结构以及相关的操作流程。通过对缓存模块的深入理解开发者可以更好地使用 Fresco 框架优化应用的图片加载性能。 二、缓存模块概述 2.1 缓存模块的作用 Fresco 框架的缓存模块主要负责图片的缓存管理包括内存缓存和磁盘缓存。其主要作用如下 减少网络请求通过缓存已经加载过的图片避免重复的网络请求从而节省网络流量。提高加载速度从缓存中获取图片比从网络下载图片要快得多能够显著提升图片的加载速度改善用户体验。降低内存压力合理的缓存策略可以有效地管理内存避免因大量图片加载导致的内存溢出问题。 2.2 缓存模块的主要组件 Fresco 框架的缓存模块主要由以下几个组件构成 内存缓存Memory Cache 用于缓存图片的解码结果存储在内存中访问速度快。磁盘缓存Disk Cache 用于缓存图片的原始数据存储在磁盘上容量较大可持久化存储。缓存键Cache Key 用于唯一标识一个缓存项确保缓存的准确性和一致性。缓存策略Cache Strategy 定义了缓存的存储和清理规则如缓存的大小限制、过期时间等。 2.3 缓存模块的架构 Fresco 框架的缓存模块采用分层架构主要分为内存缓存层和磁盘缓存层。当应用请求一张图片时首先会在内存缓存中查找如果找到则直接返回如果未找到则会在磁盘缓存中查找如果磁盘缓存中也未找到则会从网络下载图片并将其存储到磁盘缓存和内存缓存中。这种分层架构有效地提高了图片的加载效率同时也保证了缓存的一致性和可靠性。 三、内存缓存Memory Cache 3.1 内存缓存的作用和特点 内存缓存是 Fresco 框架缓存模块的重要组成部分它将图片的解码结果存储在内存中具有以下作用和特点 快速访问内存的访问速度远远高于磁盘因此从内存缓存中获取图片可以显著提高图片的加载速度。临时存储内存缓存中的数据是临时存储的当应用退出或内存不足时缓存的数据可能会被清除。容量有限由于内存资源有限内存缓存的容量通常较小需要合理管理缓存的大小避免内存溢出。 3.2 内存缓存的实现类 - LruMemoryCache Fresco 框架中内存缓存的主要实现类是 LruMemoryCache它基于 LRULeast Recently Used最近最少使用算法实现。LRU 算法的核心思想是当缓存空间不足时优先淘汰最近最少使用的缓存项。 以下是 LruMemoryCache 的部分源码分析 java // LruMemoryCache 类定义实现了 MemoryCache 接口 public class LruMemoryCacheK, V implements MemoryCacheK, V {// 缓存的最大容量private final int mMaxCacheSize;// 当前缓存的大小private int mCurrentCacheSize;// 存储缓存项的 LRU 链表private final LinkedHashMapK, V mCache;// 构造函数初始化缓存的最大容量public LruMemoryCache(int maxCacheSize) {this.mMaxCacheSize maxCacheSize;// 初始化 LRU 链表设置 accessOrder 为 true 以实现 LRU 算法this.mCache new LinkedHashMapK, V(0, 0.75f, true) {Overrideprotected boolean removeEldestEntry(Map.EntryK, V eldest) {// 当当前缓存大小超过最大容量时移除最旧的缓存项return mCurrentCacheSize mMaxCacheSize;}};}// 从缓存中获取数据Overridepublic V get(K key) {// 同步访问缓存synchronized (this) {// 从 LRU 链表中获取数据V value mCache.get(key);if (value ! null) {// 如果获取到数据更新缓存项的访问顺序mCache.get(key); }return value;}}// 向缓存中添加数据Overridepublic V put(K key, V value) {// 同步访问缓存synchronized (this) {// 计算新数据的大小int itemSize getSize(value);// 如果新数据的大小超过最大容量直接返回 nullif (itemSize mMaxCacheSize) {return null;}// 先移除旧的缓存项V oldValue mCache.remove(key);if (oldValue ! null) {// 减少当前缓存的大小mCurrentCacheSize - getSize(oldValue);}// 将新数据添加到缓存中mCache.put(key, value);// 增加当前缓存的大小mCurrentCacheSize itemSize;// 检查缓存大小是否超过最大容量如果超过则移除最旧的缓存项trimToSize(mMaxCacheSize);return oldValue;}}// 移除缓存项Overridepublic boolean remove(K key) {// 同步访问缓存synchronized (this) {// 从 LRU 链表中移除缓存项V value mCache.remove(key);if (value ! null) {// 减少当前缓存的大小mCurrentCacheSize - getSize(value);return true;}return false;}}// 调整缓存大小确保不超过最大容量private void trimToSize(int maxSize) {// 同步访问缓存synchronized (this) {while (mCurrentCacheSize maxSize) {// 获取最旧的缓存项Map.EntryK, V eldest mCache.entrySet().iterator().next();if (eldest ! null) {// 移除最旧的缓存项K key eldest.getKey();V value eldest.getValue();mCache.remove(key);// 减少当前缓存的大小mCurrentCacheSize - getSize(value);}}}}// 计算缓存项的大小private int getSize(V value) {// 这里可以根据具体的缓存项类型实现不同的大小计算逻辑return 1; } }3.2.1 源码分析 构造函数初始化缓存的最大容量 mMaxCacheSize 和存储缓存项的 LinkedHashMap。LinkedHashMap 的 accessOrder 参数设置为 true表示按照访问顺序排序从而实现 LRU 算法。get 方法从缓存中获取数据并更新缓存项的访问顺序。put 方法向缓存中添加数据先移除旧的缓存项再添加新的数据并检查缓存大小是否超过最大容量如果超过则移除最旧的缓存项。remove 方法从缓存中移除指定的缓存项并更新当前缓存的大小。trimToSize 方法调整缓存大小确保不超过最大容量。getSize 方法计算缓存项的大小具体实现可以根据缓存项的类型进行调整。 3.3 内存缓存的使用示例 以下是一个简单的使用 LruMemoryCache 的示例 java // 创建一个最大容量为 10 的内存缓存 LruMemoryCacheString, String memoryCache new LruMemoryCache(10);// 向缓存中添加数据 memoryCache.put(key1, value1); memoryCache.put(key2, value2);// 从缓存中获取数据 String value1 memoryCache.get(key1); if (value1 ! null) {System.out.println(Value for key1: value1); }// 移除缓存项 memoryCache.remove(key1);3.4 内存缓存的管理和优化 为了更好地管理和优化内存缓存Fresco 框架提供了以下几种机制 内存修剪Memory Trimming 当系统内存不足时Fresco 会自动触发内存修剪操作减少内存缓存的大小以避免应用被系统杀死。 缓存清理Cache Eviction 根据 LRU 算法当缓存空间不足时优先淘汰最近最少使用的缓存项。 缓存大小配置开发者可以根据应用的需求和设备的内存情况合理配置内存缓存的最大容量。 以下是一个内存修剪的示例代码 java // 实现 MemoryTrimmable 接口用于处理内存修剪事件 public class MyMemoryTrimmable implements MemoryTrimmable {private final LruMemoryCacheString, String memoryCache;public MyMemoryTrimmable(LruMemoryCacheString, String memoryCache) {this.memoryCache memoryCache;}Overridepublic void trim(MemoryTrimLevel trimLevel) {switch (trimLevel) {case OnCloseToDalvikHeapLimit:case OnSystemLowMemoryWhileAppInBackground:case OnSystemLowMemoryWhileAppInForeground:// 当系统内存不足时减少缓存大小memoryCache.trimToSize(memoryCache.getMaxCacheSize() / 2);break;}} }// 注册内存修剪监听器 MemoryTrimmableRegistry memoryTrimmableRegistry NoOpMemoryTrimmableRegistry.getInstance(); memoryTrimmableRegistry.registerMemoryTrimmable(new MyMemoryTrimmable(memoryCache));四、磁盘缓存Disk Cache 4.1 磁盘缓存的作用和特点 磁盘缓存是 Fresco 框架缓存模块的另一个重要组成部分它将图片的原始数据存储在磁盘上具有以下作用和特点 持久化存储磁盘缓存中的数据可以持久化存储即使应用退出或设备重启缓存的数据仍然存在。大容量存储磁盘的存储空间通常比内存大得多因此磁盘缓存可以存储更多的图片数据。访问速度较慢相比于内存缓存磁盘缓存的访问速度较慢因为需要进行磁盘 I/O 操作。 4.2 磁盘缓存的实现类 - BufferedDiskCache Fresco 框架中磁盘缓存的主要实现类是 BufferedDiskCache它基于文件系统实现将图片数据存储在磁盘文件中。 以下是 BufferedDiskCache 的部分源码分析 java // BufferedDiskCache 类定义实现了 DiskCache 接口 public class BufferedDiskCache implements DiskCache {// 磁盘缓存的目录private final File mCacheDir;// 缓存的最大容量private final long mMaxCacheSize;// 当前缓存的大小private long mCurrentCacheSize;// 存储缓存项信息的映射private final MapString, CacheEntry mCacheEntries;// 构造函数初始化缓存目录和最大容量public BufferedDiskCache(File cacheDir, long maxCacheSize) {this.mCacheDir cacheDir;this.mMaxCacheSize maxCacheSize;this.mCacheEntries new HashMap();// 初始化缓存计算当前缓存的大小initializeCache();}// 初始化缓存计算当前缓存的大小private void initializeCache() {if (!mCacheDir.exists()) {mCacheDir.mkdirs();}File[] files mCacheDir.listFiles();if (files ! null) {for (File file : files) {if (file.isFile()) {mCurrentCacheSize file.length();// 记录缓存项信息mCacheEntries.put(file.getName(), new CacheEntry(file.getName(), file.length()));}}}// 检查缓存大小是否超过最大容量如果超过则进行清理trimToSize(mMaxCacheSize);}// 从缓存中获取数据Overridepublic InputStream get(String key) {// 构建缓存文件的路径File file new File(mCacheDir, getFileName(key));if (file.exists()) {try {// 打开文件输入流return new FileInputStream(file);} catch (FileNotFoundException e) {e.printStackTrace();}}return null;}// 向缓存中添加数据Overridepublic void put(String key, InputStream data) {// 构建缓存文件的路径File file new File(mCacheDir, getFileName(key));try {// 创建文件输出流FileOutputStream fos new FileOutputStream(file);byte[] buffer new byte[1024];int bytesRead;while ((bytesRead data.read(buffer)) ! -1) {// 将数据写入文件fos.write(buffer, 0, bytesRead);}fos.close();data.close();// 更新当前缓存的大小long fileSize file.length();mCurrentCacheSize fileSize;// 记录缓存项信息mCacheEntries.put(file.getName(), new CacheEntry(file.getName(), fileSize));// 检查缓存大小是否超过最大容量如果超过则进行清理trimToSize(mMaxCacheSize);} catch (IOException e) {e.printStackTrace();}}// 移除缓存项Overridepublic boolean remove(String key) {// 构建缓存文件的路径File file new File(mCacheDir, getFileName(key));if (file.exists()) {// 删除文件boolean deleted file.delete();if (deleted) {// 更新当前缓存的大小mCurrentCacheSize - file.length();// 移除缓存项信息mCacheEntries.remove(file.getName());return true;}}return false;}// 调整缓存大小确保不超过最大容量private void trimToSize(long maxSize) {while (mCurrentCacheSize maxSize) {// 找到最旧的缓存项CacheEntry eldestEntry null;long eldestTimestamp Long.MAX_VALUE;for (CacheEntry entry : mCacheEntries.values()) {if (entry.timestamp eldestTimestamp) {eldestTimestamp entry.timestamp;eldestEntry entry;}}if (eldestEntry ! null) {// 移除最旧的缓存项File file new File(mCacheDir, eldestEntry.fileName);if (file.exists()) {boolean deleted file.delete();if (deleted) {// 更新当前缓存的大小mCurrentCacheSize - file.length();// 移除缓存项信息mCacheEntries.remove(eldestEntry.fileName);}}}}}// 根据缓存键生成文件名private String getFileName(String key) {// 这里可以使用哈希算法生成唯一的文件名return key.hashCode() .cache;}// 缓存项信息类private static class CacheEntry {final String fileName;final long size;final long timestamp;CacheEntry(String fileName, long size) {this.fileName fileName;this.size size;this.timestamp System.currentTimeMillis();}} }4.2.1 源码分析 构造函数初始化缓存目录和最大容量并调用 initializeCache 方法初始化缓存计算当前缓存的大小。initializeCache 方法检查缓存目录是否存在如果不存在则创建。遍历缓存目录下的所有文件计算当前缓存的大小并记录缓存项信息。最后检查缓存大小是否超过最大容量如果超过则进行清理。get 方法根据缓存键构建缓存文件的路径检查文件是否存在如果存在则打开文件输入流并返回。put 方法根据缓存键构建缓存文件的路径创建文件输出流将数据写入文件。更新当前缓存的大小记录缓存项信息并检查缓存大小是否超过最大容量如果超过则进行清理。remove 方法根据缓存键构建缓存文件的路径检查文件是否存在如果存在则删除文件并更新当前缓存的大小和缓存项信息。trimToSize 方法调整缓存大小确保不超过最大容量。找到最旧的缓存项删除对应的文件并更新当前缓存的大小和缓存项信息。getFileName 方法根据缓存键生成唯一的文件名这里使用哈希算法生成文件名。CacheEntry 类用于记录缓存项的信息包括文件名、大小和时间戳。 4.3 磁盘缓存的使用示例 以下是一个简单的使用 BufferedDiskCache 的示例 java // 创建磁盘缓存实例 File cacheDir new File(/sdcard/my_cache); BufferedDiskCache diskCache new BufferedDiskCache(cacheDir, 1024 * 1024 * 10); // 最大容量为 10MB// 向缓存中添加数据 try {String key image1;InputStream data new ByteArrayInputStream(Hello, World!.getBytes());diskCache.put(key, data); } catch (Exception e) {e.printStackTrace(); }// 从缓存中获取数据 try {String key image1;InputStream data diskCache.get(key);if (data ! null) {byte[] buffer new byte[1024];int bytesRead;while ((bytesRead data.read(buffer)) ! -1) {System.out.write(buffer, 0, bytesRead);}data.close();} } catch (IOException e) {e.printStackTrace(); }// 移除缓存项 boolean removed diskCache.remove(image1); if (removed) {System.out.println(Cache item removed successfully.); }4.4 磁盘缓存的管理和优化 为了更好地管理和优化磁盘缓存Fresco 框架提供了以下几种机制 缓存清理Cache Eviction 根据缓存项的时间戳优先淘汰最旧的缓存项以确保缓存空间不超过最大容量。缓存大小配置开发者可以根据应用的需求和设备的存储情况合理配置磁盘缓存的最大容量。文件管理使用合适的文件名和目录结构方便缓存文件的管理和查找。 五、缓存键Cache Key 5.1 缓存键的作用和特点 缓存键是用于唯一标识一个缓存项的字符串它在缓存模块中起着至关重要的作用。缓存键的主要作用和特点如下 唯一性每个缓存项都有一个唯一的缓存键确保缓存的准确性和一致性。确定性相同的输入应该生成相同的缓存键保证缓存的可重复性。可读性缓存键应该具有一定的可读性方便调试和管理。 5.2 缓存键的生成策略 Fresco 框架提供了多种缓存键的生成策略常见的有以下几种 基于 URI 的缓存键使用图片的 URI 作为缓存键确保不同 URI 的图片有不同的缓存项。 基于 URI 和参数的缓存键除了 URI 之外还考虑图片的请求参数如裁剪尺寸、旋转角度等确保不同参数的图片有不同的缓存项。 哈希缓存键使用哈希算法对 URI 和参数进行哈希处理生成唯一的哈希值作为缓存键减少缓存键的长度提高存储效率。 以下是一个基于 URI 和参数的缓存键生成示例 java import java.net.URI; import java.util.HashMap; import java.util.Map;// 缓存键生成器类 public class CacheKeyGenerator {// 生成缓存键的方法public static String generateCacheKey(URI uri, MapString, String params) {StringBuilder keyBuilder new StringBuilder();// 添加 URI 到缓存键keyBuilder.append(uri.toString());if (params ! null !params.isEmpty()) {// 对参数进行排序确保相同参数的顺序生成相同的缓存键java.util.TreeMapString, String sortedParams new java.util.TreeMap(params);for (Map.EntryString, String entry : sortedParams.entrySet()) {keyBuilder.append();keyBuilder.append(entry.getKey());keyBuilder.append();keyBuilder.append(entry.getValue());}}// 对缓存键进行哈希处理return hash(keyBuilder.toString());}// 哈希处理方法这里简单使用 hashCode 方法private static String hash(String input) {return String.valueOf(input.hashCode());}public static void main(String[] args) {URI uri URI.create(https://example.com/image.jpg);MapString, String params new HashMap();params.put(width, 200);params.put(height, 300);String cacheKey generateCacheKey(uri, params);System.out.println(Cache Key: cacheKey);} }5.2.1 源码分析 generateCacheKey 方法首先将 URI 添加到缓存键中然后对参数进行排序并添加到缓存键中。最后对缓存键进行哈希处理生成最终的缓存键。hash 方法这里简单使用 hashCode 方法对输入进行哈希处理实际应用中可以使用更复杂的哈希算法如 MD5、SHA-1 等。 5.3 缓存键的使用示例 在使用内存缓存和磁盘缓存时需要使用缓存键来进行数据的存储和获取。以下是一个使用缓存键的示例 java // 创建内存缓存实例 LruMemoryCacheString, String memoryCache new LruMemoryCache(10);// 生成缓存键 URI uri URI.create(https://example.com/image.jpg); MapString, String params new HashMap(); params.put(width, 200); params.put(height, 300); String cacheKey CacheKeyGenerator.generateCacheKey(uri, params);// 向内存缓存中添加数据 memoryCache.put(cacheKey, Image data);// 从内存缓存中获取数据 String data memoryCache.get(cacheKey); if (data ! null) {System.out.println(Cached data: data); }六、缓存策略Cache Strategy 6.1 缓存策略的作用和分类 缓存策略定义了缓存的存储和清理规则它在缓存模块中起着至关重要的作用。合理的缓存策略可以有效地提高缓存的命中率减少内存和磁盘的使用从而提升应用的性能。常见的缓存策略可以分为以下几类 基于时间的缓存策略根据缓存项的存储时间来决定是否清理缓存项如设置缓存项的过期时间超过过期时间的缓存项将被清理。基于大小的缓存策略根据缓存的大小来决定是否清理缓存项如设置缓存的最大容量当缓存大小超过最大容量时优先清理最近最少使用的缓存项。基于访问频率的缓存策略根据缓存项的访问频率来决定是否清理缓存项如优先清理访问频率较低的缓存项。 6.2 基于时间的缓存策略实现 以下是一个简单的基于时间的缓存策略实现示例 java import java.util.HashMap; import java.util.Map;// 基于时间的缓存类 public class TimeBasedCacheK, V {// 存储缓存项的映射private final MapK, CacheEntryV cache;// 缓存项的过期时间毫秒private final long expirationTime;// 构造函数初始化过期时间public TimeBasedCache(long expirationTime) {this.cache new HashMap();this.expirationTime expirationTime;}// 从缓存中获取数据public V get(K key) {CacheEntryV entry cache.get(key);if (entry ! null) {// 检查缓存项是否过期if (System.currentTimeMillis() - entry.timestamp expirationTime) {return entry.value;} else {// 缓存项已过期移除缓存项cache.remove(key);}}return null;}// 向缓存中添加数据public void put(K key, V value) {// 创建新的缓存项CacheEntryV entry new CacheEntry(value, System.currentTimeMillis());cache.put(key, entry);}// 缓存项信息类private static class CacheEntryV {final V value;final long timestamp;CacheEntry(V value, long timestamp) {this.value value;this.timestamp timestamp;}}public static void main(String[] args) {// 创建一个过期时间为 10 秒的缓存TimeBasedCacheString, String cache new TimeBasedCache(10 * 1000);// 向缓存中添加数据cache.put(key1, value1);// 从缓存中获取数据String value cache.get(key1);ifjava import java.util.HashMap; import java.util.Map;// 基于时间的缓存类 public class TimeBasedCacheK, V {// 存储缓存项的映射private final MapK, CacheEntryV cache;// 缓存项的过期时间毫秒private final long expirationTime;// 构造函数初始化过期时间public TimeBasedCache(long expirationTime) {this.cache new HashMap();this.expirationTime expirationTime;}// 从缓存中获取数据public V get(K key) {CacheEntryV entry cache.get(key);if (entry ! null) {// 检查缓存项是否过期if (System.currentTimeMillis() - entry.timestamp expirationTime) {return entry.value;} else {// 缓存项已过期移除缓存项cache.remove(key);}}return null;}// 向缓存中添加数据public void put(K key, V value) {// 创建新的缓存项CacheEntryV entry new CacheEntry(value, System.currentTimeMillis());cache.put(key, entry);}// 缓存项信息类private static class CacheEntryV {final V value;final long timestamp;CacheEntry(V value, long timestamp) {this.value value;this.timestamp timestamp;}}public static void main(String[] args) {// 创建一个过期时间为 10 秒的缓存TimeBasedCacheString, String cache new TimeBasedCache(10 * 1000);// 向缓存中添加数据cache.put(key1, value1);// 从缓存中获取数据String value cache.get(key1);if (value ! null) {System.out.println(Cached value: value);}try {// 等待 11 秒让缓存项过期Thread.sleep(11 * 1000);} catch (InterruptedException e) {e.printStackTrace();}// 再次从缓存中获取数据value cache.get(key1);if (value null) {System.out.println(Cache item has expired.);}} }6.2.1 源码分析 构造函数初始化一个 HashMap 用于存储缓存项并设置缓存项的过期时间。get 方法从缓存中获取指定键对应的值。首先检查缓存项是否存在如果存在则判断其是否过期。若未过期则返回值若已过期则移除该缓存项并返回 null。put 方法向缓存中添加新的键值对。创建一个新的 CacheEntry 对象记录当前时间戳并将其存入 HashMap 中。CacheEntry 类用于存储缓存项的值和存储时间戳。main 方法创建一个过期时间为 10 秒的缓存实例添加一个缓存项获取该缓存项然后等待 11 秒使缓存项过期再次获取该缓存项验证过期机制。 6.3 基于大小的缓存策略实现 Fresco 框架中的 LruMemoryCache 就是基于大小的缓存策略的典型实现这里再给出一个简化版的示例 java import java.util.LinkedHashMap; import java.util.Map;// 基于大小的缓存类 public class SizeBasedCacheK, V {// 缓存的最大容量private final int maxSize;// 存储缓存项的 LRU 链表private final LinkedHashMapK, V cache;// 构造函数初始化最大容量public SizeBasedCache(int maxSize) {this.maxSize maxSize;// 初始化 LRU 链表设置 accessOrder 为 true 以实现 LRU 算法this.cache new LinkedHashMapK, V(0, 0.75f, true) {Overrideprotected boolean removeEldestEntry(Map.EntryK, V eldest) {// 当当前缓存大小超过最大容量时移除最旧的缓存项return size() maxSize;}};}// 从缓存中获取数据public V get(K key) {return cache.get(key);}// 向缓存中添加数据public void put(K key, V value) {cache.put(key, value);}public static void main(String[] args) {// 创建一个最大容量为 3 的缓存SizeBasedCacheString, String cache new SizeBasedCache(3);// 向缓存中添加数据cache.put(key1, value1);cache.put(key2, value2);cache.put(key3, value3);// 此时缓存已满System.out.println(Cache size: cache.cache.size());// 再添加一个新的缓存项会触发 LRU 机制移除最旧的缓存项cache.put(key4, value4);System.out.println(Cache size after adding key4: cache.cache.size());// 检查最旧的缓存项是否已被移除if (cache.get(key1) null) {System.out.println(Key1 has been removed from cache.);}} }6.3.1 源码分析 构造函数初始化缓存的最大容量和 LinkedHashMap。LinkedHashMap 的 accessOrder 参数设置为 true使其按照访问顺序排序从而实现 LRU 算法。get 方法从缓存中获取指定键对应的值。put 方法向缓存中添加新的键值对。如果添加后缓存大小超过最大容量removeEldestEntry 方法会被调用移除最旧的缓存项。main 方法创建一个最大容量为 3 的缓存实例添加 3 个缓存项使缓存已满再添加一个新的缓存项验证 LRU 机制是否移除了最旧的缓存项。 6.4 基于访问频率的缓存策略实现 java import java.util.HashMap; import java.util.Map; import java.util.PriorityQueue;// 基于访问频率的缓存类 public class FrequencyBasedCacheK, V {// 缓存的最大容量private final int maxSize;// 存储缓存项的映射private final MapK, CacheEntryV cache;// 按访问频率排序的优先队列private final PriorityQueueCacheEntryV frequencyQueue;// 构造函数初始化最大容量public FrequencyBasedCache(int maxSize) {this.maxSize maxSize;this.cache new HashMap();this.frequencyQueue new PriorityQueue((a, b) - a.accessCount - b.accessCount);}// 从缓存中获取数据public V get(K key) {CacheEntryV entry cache.get(key);if (entry ! null) {// 增加访问次数entry.accessCount;// 从优先队列中移除该缓存项frequencyQueue.remove(entry);// 重新插入优先队列以更新排序frequencyQueue.add(entry);return entry.value;}return null;}// 向缓存中添加数据public void put(K key, V value) {if (cache.size() maxSize) {// 缓存已满移除访问频率最低的缓存项CacheEntryV leastFrequentEntry frequencyQueue.poll();if (leastFrequentEntry ! null) {cache.remove(leastFrequentEntry.key);}}// 创建新的缓存项CacheEntryV newEntry new CacheEntry(key, value, 1);cache.put(key, newEntry);frequencyQueue.add(newEntry);}// 缓存项信息类private static class CacheEntryV {final K key;final V value;int accessCount;CacheEntry(K key, V value, int accessCount) {this.key key;this.value value;this.accessCount accessCount;}}public static void main(String[] args) {// 创建一个最大容量为 3 的缓存FrequencyBasedCacheString, String cache new FrequencyBasedCache(3);// 向缓存中添加数据cache.put(key1, value1);cache.put(key2, value2);cache.put(key3, value3);// 访问 key1 两次使其访问频率增加cache.get(key1);cache.get(key1);// 再添加一个新的缓存项会移除访问频率最低的缓存项cache.put(key4, value4);// 检查访问频率最低的缓存项是否已被移除if (cache.get(key2) null) {System.out.println(Key2 has been removed from cache.);}} }6.4.1 源码分析 构造函数初始化缓存的最大容量、HashMap 用于存储缓存项以及一个优先队列 PriorityQueue 用于按访问频率对缓存项进行排序。get 方法从缓存中获取指定键对应的值。如果缓存项存在增加其访问次数从优先队列中移除该缓存项再重新插入以更新排序。put 方法向缓存中添加新的键值对。如果缓存已满移除优先队列中访问频率最低的缓存项。创建新的缓存项并添加到 HashMap 和优先队列中。CacheEntry 类用于存储缓存项的键、值和访问次数。main 方法创建一个最大容量为 3 的缓存实例添加 3 个缓存项增加 key1 的访问频率再添加一个新的缓存项验证是否移除了访问频率最低的缓存项。 七、缓存模块的交互流程 7.1 图片请求时的缓存查找流程 当应用发起一个图片请求时Fresco 框架的缓存模块会按照以下流程进行缓存查找 java // 图片请求处理类 public class ImageRequestProcessor {private final LruMemoryCacheString, Image memoryCache;private final BufferedDiskCache diskCache;public ImageRequestProcessor(LruMemoryCacheString, Image memoryCache, BufferedDiskCache diskCache) {this.memoryCache memoryCache;this.diskCache diskCache;}public Image processRequest(String imageUrl) {// 生成缓存键String cacheKey CacheKeyGenerator.generateCacheKey(imageUrl, null);// 首先在内存缓存中查找Image image memoryCache.get(cacheKey);if (image ! null) {System.out.println(Image found in memory cache.);return image;}// 内存缓存中未找到在磁盘缓存中查找InputStream diskData diskCache.get(cacheKey);if (diskData ! null) {System.out.println(Image found in disk cache.);// 从磁盘数据中解码图片image decodeImage(diskData);// 将图片存入内存缓存memoryCache.put(cacheKey, image);return image;}// 磁盘缓存中也未找到从网络下载图片System.out.println(Image not found in cache, downloading from network...);image downloadImage(imageUrl);if (image ! null) {// 将图片存入磁盘缓存diskCache.put(cacheKey, encodeImage(image));// 将图片存入内存缓存memoryCache.put(cacheKey, image);}return image;}private Image decodeImage(InputStream data) {// 解码图片的逻辑这里简单返回 null 表示未实现return null;}private InputStream encodeImage(Image image) {// 编码图片的逻辑这里简单返回 null 表示未实现return null;}private Image downloadImage(String imageUrl) {// 从网络下载图片的逻辑这里简单返回 null 表示未实现return null;}public static void main(String[] args) {// 创建内存缓存和磁盘缓存实例LruMemoryCacheString, Image memoryCache new LruMemoryCache(10);File cacheDir new File(/sdcard/my_cache);BufferedDiskCache diskCache new BufferedDiskCache(cacheDir, 1024 * 1024 * 10);ImageRequestProcessor processor new ImageRequestProcessor(memoryCache, diskCache);// 处理图片请求Image image processor.processRequest(https://example.com/image.jpg);if (image ! null) {System.out.println(Image loaded successfully.);}} }7.1.1 源码分析 构造函数初始化内存缓存和磁盘缓存实例。 processRequest 方法 生成图片的缓存键。首先在内存缓存中查找图片如果找到则直接返回。若内存缓存中未找到在磁盘缓存中查找。若找到解码图片并将其存入内存缓存。若磁盘缓存中也未找到从网络下载图片将其存入磁盘缓存和内存缓存。 decodeImage 方法用于解码图片这里未实现具体逻辑。 encodeImage 方法用于编码图片这里未实现具体逻辑。 downloadImage 方法用于从网络下载图片这里未实现具体逻辑。 main 方法创建内存缓存、磁盘缓存和请求处理器实例处理图片请求并输出结果。 7.2 缓存更新和清理流程 7.2.1 缓存更新 当图片数据发生变化时需要更新缓存。以下是一个简单的缓存更新示例 java public class CacheUpdater {private final LruMemoryCacheString, Image memoryCache;private final BufferedDiskCache diskCache;public CacheUpdater(LruMemoryCacheString, Image memoryCache, BufferedDiskCache diskCache) {this.memoryCache memoryCache;this.diskCache diskCache;}public void updateCache(String imageUrl, Image newImage) {// 生成缓存键String cacheKey CacheKeyGenerator.generateCacheKey(imageUrl, null);// 更新内存缓存memoryCache.put(cacheKey, newImage);// 更新磁盘缓存diskCache.put(cacheKey, encodeImage(newImage));}private InputStream encodeImage(Image image) {// 编码图片的逻辑这里简单返回 null 表示未实现return null;}public static void main(String[] args) {// 创建内存缓存和磁盘缓存实例LruMemoryCacheString, Image memoryCache new LruMemoryCache(10);File cacheDir new File(/sdcard/my_cache);BufferedDiskCache diskCache new BufferedDiskCache(cacheDir, 1024 * 1024 * 10);CacheUpdater updater new CacheUpdater(memoryCache, diskCache);// 模拟新的图片数据Image newImage null;updater.updateCache(https://example.com/image.jpg, newImage);} }7.2.1.1 源码分析 构造函数初始化内存缓存和磁盘缓存实例。 updateCache 方法 生成图片的缓存键。更新内存缓存中的图片数据。更新磁盘缓存中的图片数据。 encodeImage 方法用于编码图片这里未实现具体逻辑。 main 方法创建内存缓存、磁盘缓存和缓存更新器实例模拟更新图片缓存。 7.2.2 缓存清理 缓存清理可以根据不同的策略进行如定期清理、内存不足时清理等。以下是一个简单的定期清理示例 java import java.util.Timer; import java.util.TimerTask;public class CacheCleaner {private final LruMemoryCacheString, Image memoryCache;private final BufferedDiskCache diskCache;public CacheCleaner(LruMemoryCacheString, Image memoryCache, BufferedDiskCache diskCache) {this.memoryCache memoryCache;this.diskCache diskCache;}public void startPeriodicCleaning(long interval) {Timer timer new Timer();timer.schedule(new TimerTask() {Overridepublic void run() {// 清理内存缓存memoryCache.trimToSize(memoryCache.getMaxCacheSize() / 2);// 清理磁盘缓存diskCache.trimToSize(diskCache.getMaxCacheSize() / 2);}}, 0, interval);}public static void main(String[] args) {// 创建内存缓存和磁盘缓存实例LruMemoryCacheString, Image memoryCache new LruMemoryCache(10);File cacheDir new File(/sdcard/my_cache);BufferedDiskCache diskCache new BufferedDiskCache(cacheDir, 1024 * 1024 * 10);CacheCleaner cleaner new CacheCleaner(memoryCache, diskCache);// 开始定期清理每隔 1 小时清理一次cleaner.startPeriodicCleaning(1000 * 60 * 60);} }7.2.2.1 源码分析 构造函数初始化内存缓存和磁盘缓存实例。startPeriodicCleaning 方法使用 Timer 和 TimerTask 实现定期清理。每隔指定的时间间隔调用 trimToSize 方法清理内存缓存和磁盘缓存将缓存大小调整为最大容量的一半。main 方法创建内存缓存、磁盘缓存和缓存清理器实例开始定期清理每隔 1 小时清理一次。 八、缓存模块的性能优化 8.1 缓存命中率优化 合理设置缓存大小根据应用的使用场景和设备的内存、存储情况合理设置内存缓存和磁盘缓存的大小。如果缓存太小可能会导致频繁的缓存失效和重新加载如果缓存太大可能会占用过多的系统资源。优化缓存键生成策略确保缓存键的生成能够准确反映图片的唯一性避免因缓存键冲突导致的缓存命中率下降。可以考虑使用更复杂的哈希算法和更多的请求参数来生成缓存键。使用预加载机制对于一些经常使用的图片可以提前将其加载到缓存中提高缓存命中率。例如在应用启动时预加载一些常用的图片。 8.2 缓存读写性能优化 内存缓存优化 使用高效的数据结构如 LruMemoryCache 中使用的 LinkedHashMap可以快速地进行插入、删除和查找操作。减少内存拷贝在存储和获取图片数据时尽量减少内存拷贝的次数提高内存使用效率。 磁盘缓存优化 采用异步读写使用异步 I/O 操作进行磁盘读写避免阻塞主线程提高应用的响应速度。合理设置缓存文件的存储结构如按图片类型、时间等进行分类存储方便查找和管理。 8.3 缓存清理策略优化 智能清理根据缓存项的使用频率、过期时间等因素智能地选择要清理的缓存项。例如优先清理访问频率低、过期时间长的缓存项。增量清理在进行缓存清理时采用增量清理的方式每次只清理一部分缓存项避免一次性清理过多缓存项导致的性能波动。 九、缓存模块的扩展性分析 9.1 自定义缓存实现 开发者可以根据自己的需求自定义缓存实现只需要实现 MemoryCache 或 DiskCache 接口即可。以下是一个简单的自定义内存缓存实现示例 java import com.facebook.common.references.CloseableReference; import com.facebook.imagepipeline.cache.CacheKey; import com.facebook.imagepipeline.cache.MemoryCache; import com.facebook.imagepipeline.image.CloseableImage;import java.util.HashMap; import java.util.Map;// 自定义内存缓存实现 public class CustomMemoryCache implements MemoryCacheCacheKey, CloseableReferenceCloseableImage {private final MapCacheKey, CloseableReferenceCloseableImage cache;public CustomMemoryCache() {this.cache new HashMap();}Overridepublic CloseableReferenceCloseableImage get(CacheKey key) {return cache.get(key);}Overridepublic CloseableReferenceCloseableImage cache(CacheKey key, CloseableReferenceCloseableImage value) {cache.put(key, value);return value;}Overridepublic boolean contains(CacheKey key) {return cache.containsKey(key);}Overridepublic boolean remove(CacheKey key) {return cache.remove(key) ! null;}Overridepublic int removeAll(RemoveConditionCacheKey condition) {int removedCount 0;for (Map.EntryCacheKey, CloseableReferenceCloseableImage entry : cache.entrySet()) {if (condition.shouldRemove(entry.getKey())) {cache.remove(entry.getKey());removedCount;}}return removedCount;} }9.1.1 源码分析 构造函数初始化一个 HashMap 用于存储缓存项。get 方法从缓存中获取指定键对应的值。cache 方法向缓存中添加新的键值对。contains 方法检查缓存中是否包含指定的键。remove 方法从缓存中移除指定的键值对。removeAll 方法根据指定的条件移除缓存项。 9.2 自定义缓存策略 开发者也可以自定义缓存策略只需要实现相应的缓存策略接口即可。以下是一个简单的自定义基于时间和大小的混合缓存策略实现示例 java import com.facebook.common.references.CloseableReference; import com.facebook.imagepipeline.cache.CacheKey; import com.facebook.imagepipeline.cache.MemoryCache; import com.facebook.imagepipeline.image.CloseableImage;import java.util.*;// 自定义混合缓存策略 public class CustomCacheStrategy implements MemoryCacheCacheKey, CloseableReferenceCloseableImage {private final MapCacheKey, CacheEntryCloseableReferenceCloseableImage cache;private final int maxSize;private final long expirationTime;public CustomCacheStrategy(int maxSize, long expirationTime) {this.cache new HashMap();this.maxSize maxSize;this.expirationTime expirationTime;}Overridepublic CloseableReferenceCloseableImage get(CacheKey key) {CacheEntryCloseableReferenceCloseableImage entry cache.get(key);if (entry ! null) {if (System.currentTimeMillis() - entry.timestamp expirationTime) {return entry.value;} else {cache.remove(key);}}return null;}Overridepublic CloseableReferenceCloseableImage cache(CacheKey key, CloseableReferenceCloseableImage value) {if (cache.size() maxSize) {// 按时间排序移除最旧的缓存项ListCacheEntryCloseableReferenceCloseableImage entries new ArrayList(cache.values());entries.sort((a, b) - Long.compare(a.timestamp, b.timestamp));CacheEntryCloseableReferenceCloseableImage oldestEntry entries.get(0);cache.remove(oldestEntry.key);}CacheEntryCloseableReferenceCloseableImage newEntry new CacheEntry(key, value, System.currentTimeMillis());cache.put(key, newEntry);return value;}Overridepublic boolean contains(CacheKey key) {CacheEntryCloseableReferenceCloseableImage entry cache.get(key);return entry ! null System.currentTimeMillis() - entry.timestamp expirationTime;}Overridepublic boolean remove(CacheKey key) {return cache.remove(key) ! null;}Overridepublic int removeAll(RemoveConditionCacheKey condition) {int removedCount 0;for (Map.EntryCacheKey, CacheEntryCloseableReferenceCloseableImage entry : cache.entrySet()) {if (condition.shouldRemove(entry.getKey())) {cache.remove(entry.getKey());removedCount;}}return removedCount;}private static class CacheEntryV {final CacheKey key;final V value;final long timestamp;CacheEntry(CacheKey key, V value, long timestamp) {this.key key;this.value value;this.timestamp timestamp;}} }9.2.1 源码分析 构造函数初始化缓存的最大容量和缓存项的过期时间。 get 方法从缓存中获取指定键对应的值。检查缓存项是否过期若过期则移除该缓存项。 cache 方法向缓存中添加新的键值对。如果缓存已满按时间排序移除最旧的缓存项。 contains 方法检查缓存中是否包含指定的 java import com.facebook.common.references.CloseableReference; import com.facebook.imagepipeline.cache.CacheKey; import com.facebook.imagepipeline.cache.MemoryCache; import com.facebook.imagepipeline.image.CloseableImage;import java.util.*;// 自定义混合缓存策略 public class CustomCacheStrategy implements MemoryCacheCacheKey, CloseableReferenceCloseableImage {private final MapCacheKey, CacheEntryCloseableReferenceCloseableImage cache;private final int maxSize;private final long expirationTime;public CustomCacheStrategy(int maxSize, long expirationTime) {this.cache new HashMap();this.maxSize maxSize;this.expirationTime expirationTime;}Overridepublic CloseableReferenceCloseableImage get(CacheKey key) {CacheEntryCloseableReferenceCloseableImage entry cache.get(key);if (entry ! null) {if (System.currentTimeMillis() - entry.timestamp expirationTime) {return entry.value;} else {cache.remove(key);}}return null;}Overridepublic CloseableReferenceCloseableImage cache(CacheKey key, CloseableReferenceCloseableImage value) {if (cache.size() maxSize) {// 按时间排序移除最旧的缓存项ListCacheEntryCloseableReferenceCloseableImage entries new ArrayList(cache.values());entries.sort((a, b) - Long.compare(a.timestamp, b.timestamp));CacheEntryCloseableReferenceCloseableImage oldestEntry entries.get(0);cache.remove(oldestEntry.key);}CacheEntryCloseableReferenceCloseableImage newEntry new CacheEntry(key, value, System.currentTimeMillis());cache.put(key, newEntry);return value;}Overridepublic boolean contains(CacheKey key) {CacheEntryCloseableReferenceCloseableImage entry cache.get(key);return entry ! null System.currentTimeMillis() - entry.timestamp expirationTime;}Overridepublic boolean remove(CacheKey key) {return cache.remove(key) ! null;}Overridepublic int removeAll(RemoveConditionCacheKey condition) {int removedCount 0;for (Map.EntryCacheKey, CacheEntryCloseableReferenceCloseableImage entry : cache.entrySet()) {if (condition.shouldRemove(entry.getKey())) {cache.remove(entry.getKey());removedCount;}}return removedCount;}private static class CacheEntryV {final CacheKey key;final V value;final long timestamp;CacheEntry(CacheKey key, V value, long timestamp) {this.key key;this.value value;this.timestamp timestamp;}} }9.2.1 源码分析 contains 方法 此方法用于检查缓存中是否包含指定的键。它首先通过 cache.get(key) 尝试获取对应的缓存项。若缓存项存在会进一步检查该缓存项是否过期。通过比较当前时间与缓存项存储时间戳的差值和设定的过期时间 expirationTime若未过期则返回 true否则返回 false。 remove 方法 该方法用于从缓存中移除指定键的缓存项。它调用 cache.remove(key) 尝试移除对应的键值对若移除成功则返回 true反之返回 false。 removeAll 方法 该方法可根据指定的条件移除缓存项。它遍历 cache 中的所有键值对对于每个键值对调用 condition.shouldRemove(entry.getKey()) 判断是否需要移除。若需要移除则调用 cache.remove(entry.getKey()) 移除该键值对并将移除计数 removedCount 加 1。最后返回移除的缓存项数量。 CacheEntry 类 这是一个内部静态类用于封装缓存项的信息。包含缓存键 key、缓存值 value 以及存储时间戳 timestamp。其构造函数用于初始化这些信息确保每个缓存项都能记录其存储时间以便后续进行过期检查和排序操作。 9.3 与其他组件的集成扩展性 Fresco 缓存模块具备良好的扩展性能够与其他组件进行集成以满足不同的业务需求。 9.3.1 与网络请求组件的集成 Fresco 可以与各种网络请求组件集成当缓存中未找到所需图片时通过网络请求组件从网络下载图片。以下是一个简单的与 OkHttp 集成的示例 java import com.facebook.common.executors.CallerThreadExecutor; import com.facebook.common.references.CloseableReference; import com.facebook.datasource.DataSource; import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory; import com.facebook.imagepipeline.core.ImagePipeline; import com.facebook.imagepipeline.core.ImagePipelineConfig; import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; import com.facebook.imagepipeline.image.CloseableImage; import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequestBuilder; import okhttp3.OkHttpClient;import android.graphics.Bitmap; import android.os.Bundle; import android.widget.ImageView; import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private ImageView imageView;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);imageView findViewById(R.id.imageView);// 创建 OkHttp 客户端OkHttpClient okHttpClient new OkHttpClient();// 使用 OkHttp 配置 ImagePipelineImagePipelineConfig config OkHttpImagePipelineConfigFactory.newBuilder(this, okHttpClient).build();// 初始化 FrescoFresco.initialize(this, config);// 创建图片请求ImageRequest request ImageRequestBuilder.newBuilderWithSource(Uri.parse(https://example.com/image.jpg)).build();// 获取 ImagePipeline 实例ImagePipeline imagePipeline Fresco.getImagePipeline();// 获取数据源DataSourceCloseableReferenceCloseableImage dataSource imagePipeline.fetchDecodedImage(request, this);// 订阅数据源dataSource.subscribe(new BaseBitmapDataSubscriber() {Overrideprotected void onNewResultImpl(Bitmap bitmap) {if (bitmap ! null) {imageView.setImageBitmap(bitmap);}}Overrideprotected void onFailureImpl(DataSourceCloseableReferenceCloseableImage dataSource) {// 处理失败情况}}, CallerThreadExecutor.getInstance());} }9.3.1.1 源码分析 创建 OkHttp 客户端使用 OkHttpClient 创建一个 OkHttp 客户端实例用于处理网络请求。配置 ImagePipeline通过 OkHttpImagePipelineConfigFactory 使用 OkHttp 客户端配置 ImagePipelineConfig确保 Fresco 使用 OkHttp 进行网络请求。初始化 Fresco调用 Fresco.initialize 方法传入配置好的 ImagePipelineConfig 对 Fresco 进行初始化。创建图片请求使用 ImageRequestBuilder 创建一个图片请求指定图片的来源 URL。获取数据源通过 ImagePipeline 的 fetchDecodedImage 方法获取图片的数据源。订阅数据源使用 BaseBitmapDataSubscriber 订阅数据源当图片加载成功时将图片显示在 ImageView 上若加载失败则处理相应的失败情况。 9.3.2 与数据加密组件的集成 为了保证缓存数据的安全性可以将 Fresco 缓存模块与数据加密组件集成。以下是一个简单的示例展示如何在存储和读取缓存数据时进行加密和解密 java import com.facebook.common.references.CloseableReference; import com.facebook.imagepipeline.cache.CacheKey; import com.facebook.imagepipeline.cache.DiskCache; import com.facebook.imagepipeline.image.EncodedImage;import java.io.*; import java.security.Key; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey;// 加密磁盘缓存实现 public class EncryptedDiskCache implements DiskCache {private final DiskCache delegate;private final Cipher encryptCipher;private final Cipher decryptCipher;public EncryptedDiskCache(DiskCache delegate) throws Exception {this.delegate delegate;// 生成加密密钥KeyGenerator keyGen KeyGenerator.getInstance(AES);keyGen.init(128, new SecureRandom());SecretKey secretKey keyGen.generateKey();// 初始化加密和解密 CipherencryptCipher Cipher.getInstance(AES);encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey);decryptCipher Cipher.getInstance(AES);decryptCipher.init(Cipher.DECRYPT_MODE, secretKey);}Overridepublic CloseableReferenceEncodedImage get(CacheKey key) {CloseableReferenceEncodedImage result delegate.get(key);if (result ! null) {try {EncodedImage encodedImage result.get();InputStream inputStream encodedImage.getInputStream();CipherInputStream cipherInputStream new CipherInputStream(inputStream, decryptCipher);encodedImage.setInputStream(cipherInputStream);} catch (Exception e) {e.printStackTrace();}}return result;}Overridepublic void put(CacheKey key, EncodedImage encodedImage) {try {InputStream inputStream encodedImage.getInputStream();ByteArrayOutputStream byteArrayOutputStream new ByteArrayOutputStream();CipherOutputStream cipherOutputStream new CipherOutputStream(byteArrayOutputStream, encryptCipher);byte[] buffer new byte[1024];int bytesRead;while ((bytesRead inputStream.read(buffer)) ! -1) {cipherOutputStream.write(buffer, 0, bytesRead);}cipherOutputStream.close();ByteArrayInputStream encryptedInputStream new ByteArrayInputStream(byteArrayOutputStream.toByteArray());EncodedImage encryptedEncodedImage EncodedImage.wrapStream(encryptedInputStream, encodedImage.getSize());delegate.put(key, encryptedEncodedImage);} catch (Exception e) {e.printStackTrace();}}Overridepublic boolean containsSync(CacheKey key) {return delegate.containsSync(key);}Overridepublic void remove(CacheKey key) {delegate.remove(key);}Overridepublic void clearAll() {delegate.clearAll();} }9.3.2.1 源码分析 构造函数 接收一个 DiskCache 实例作为委托对象用于实际的缓存操作。使用 KeyGenerator 生成一个 AES 加密密钥。初始化加密和解密的 Cipher 对象分别用于加密和解密缓存数据。 get 方法 调用委托对象的 get 方法获取缓存的图片数据。若获取到数据使用 CipherInputStream 对数据进行解密并更新 EncodedImage 的输入流。 put 方法 从 EncodedImage 中获取输入流使用 CipherOutputStream 对数据进行加密。将加密后的数据封装成新的 EncodedImage 对象并调用委托对象的 put 方法将其存入缓存。 containsSync 方法直接调用委托对象的 containsSync 方法检查缓存中是否包含指定的键。 remove 方法直接调用委托对象的 remove 方法移除指定键的缓存项。 clearAll 方法直接调用委托对象的 clearAll 方法清空所有缓存项。 十、缓存模块的错误处理与调试 10.1 错误处理机制 在缓存模块中可能会遇到各种错误如磁盘读写错误、内存不足等。Fresco 提供了相应的错误处理机制确保在出现错误时能够进行恰当的处理。 10.1.1 磁盘缓存错误处理 在磁盘缓存操作中可能会出现文件读写错误。以下是一个处理磁盘缓存写入错误的示例 java import com.facebook.common.references.CloseableReference; import com.facebook.imagepipeline.cache.CacheKey; import com.facebook.imagepipeline.cache.DiskCache; import com.facebook.imagepipeline.image.EncodedImage;import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream;// 增强的磁盘缓存实现处理写入错误 public class EnhancedDiskCache implements DiskCache {private final DiskCache delegate;public EnhancedDiskCache(DiskCache delegate) {this.delegate delegate;}Overridepublic CloseableReferenceEncodedImage get(CacheKey key) {return delegate.get(key);}Overridepublic void put(CacheKey key, EncodedImage encodedImage) {try {delegate.put(key, encodedImage);} catch (Exception e) {// 处理写入错误handleWriteError(e);}}private void handleWriteError(Exception e) {// 记录错误日志System.err.println(Disk cache write error: e.getMessage());// 可以添加其他处理逻辑如重试机制}Overridepublic boolean containsSync(CacheKey key) {return delegate.containsSync(key);}Overridepublic void remove(CacheKey key) {delegate.remove(key);}Overridepublic void clearAll() {delegate.clearAll();} }10.1.1.1 源码分析 构造函数接收一个 DiskCache 实例作为委托对象用于实际的缓存操作。put 方法调用委托对象的 put 方法将图片数据存入磁盘缓存。若出现异常调用 handleWriteError 方法处理写入错误。handleWriteError 方法记录错误日志打印错误信息。开发者可以在此方法中添加其他处理逻辑如重试机制以提高系统的健壮性。其他方法get、containsSync、remove 和 clearAll 方法直接调用委托对象的相应方法。 10.1.2 内存缓存错误处理 在内存缓存操作中可能会出现内存不足的情况。以下是一个处理内存缓存溢出错误的示例 java import com.facebook.common.references.CloseableReference; import com.facebook.imagepipeline.cache.CacheKey; import com.facebook.imagepipeline.cache.MemoryCache; import com.facebook.imagepipeline.image.CloseableImage;import java.util.Map; import java.util.concurrent.ConcurrentHashMap;// 增强的内存缓存实现处理内存溢出错误 public class EnhancedMemoryCache implements MemoryCacheCacheKey, CloseableReferenceCloseableImage {private final MemoryCacheCacheKey, CloseableReferenceCloseableImage delegate;private final MapCacheKey, CloseableReferenceCloseableImage tempCache;public EnhancedMemoryCache(MemoryCacheCacheKey, CloseableReferenceCloseableImage delegate) {this.delegate delegate;this.tempCache new ConcurrentHashMap();}Overridepublic CloseableReferenceCloseableImage get(CacheKey key) {CloseableReferenceCloseableImage result delegate.get(key);if (result null) {result tempCache.get(key);}return result;}Overridepublic CloseableReferenceCloseableImage cache(CacheKey key, CloseableReferenceCloseableImage value) {try {return delegate.cache(key, value);} catch (OutOfMemoryError e) {// 处理内存溢出错误handleOutOfMemoryError(e, key, value);return null;}}private void handleOutOfMemoryError(OutOfMemoryError e, CacheKey key, CloseableReferenceCloseableImage value) {// 记录错误日志System.err.println(Memory cache out of memory error: e.getMessage());// 将数据存入临时缓存tempCache.put(key, value);// 可以添加其他处理逻辑如清理部分缓存}Overridepublic boolean contains(CacheKey key) {return delegate.contains(key) || tempCache.containsKey(key);}Overridepublic boolean remove(CacheKey key) {boolean result delegate.remove(key);result result || tempCache.remove(key) ! null;return result;}Overridepublic int removeAll(RemoveConditionCacheKey condition) {int removedCount delegate.removeAll(condition);for (Map.EntryCacheKey, CloseableReferenceCloseableImage entry : tempCache.entrySet()) {if (condition.shouldRemove(entry.getKey())) {tempCache.remove(entry.getKey());removedCount;}}return removedCount;} }10.1.2.1 源码分析 构造函数接收一个 MemoryCache 实例作为委托对象用于实际的缓存操作。同时初始化一个临时缓存 tempCache用于在内存溢出时存储数据。get 方法先从委托对象的缓存中获取数据若未找到则从临时缓存中获取。cache 方法调用委托对象的 cache 方法将数据存入内存缓存。若出现 OutOfMemoryError 异常调用 handleOutOfMemoryError 方法处理内存溢出错误。handleOutOfMemoryError 方法记录错误日志将数据存入临时缓存。开发者可以在此方法中添加其他处理逻辑如清理部分缓存以释放内存。contains 方法检查委托对象的缓存或临时缓存中是否包含指定的键。remove 方法从委托对象的缓存和临时缓存中移除指定的键值对。removeAll 方法根据指定的条件从委托对象的缓存和临时缓存中移除缓存项。 10.2 调试技巧 在开发和调试过程中以下技巧可以帮助开发者更好地理解和排查缓存模块的问题。 10.2.1 日志调试 Fresco 提供了详细的日志输出开发者可以通过设置日志级别来查看不同详细程度的日志信息。以下是一个设置日志级别的示例 java import com.facebook.common.logging.FLog;// 设置日志级别为 VERBOSE FLog.setMinimumLoggingLevel(FLog.VERBOSE);10.2.1.1 源码分析 FLog 是 Fresco 中用于日志记录的类通过调用 setMinimumLoggingLevel 方法并传入 FLog.VERBOSE可以将日志级别设置为详细模式从而查看最详细的日志信息帮助开发者定位问题。 10.2.2 性能监测 开发者可以使用 Android Studio 的性能监测工具来监测缓存模块的性能。例如使用 Memory Profiler 监测内存缓存的使用情况使用 Disk Profiler 监测磁盘缓存的读写操作。 10.2.3 断点调试 在关键代码处设置断点逐步执行代码观察变量的值和程序的执行流程有助于深入理解缓存模块的工作原理和排查问题。例如在 get 和 put 方法中设置断点观察缓存的读取和写入操作。 十一、缓存模块的未来发展趋势 11.1 对新存储技术的支持 随着存储技术的不断发展如固态硬盘SSD、分布式存储等Fresco 缓存模块可能会增加对这些新存储技术的支持以提高缓存的读写性能和可靠性。 11.2 智能化缓存策略 未来的缓存策略可能会更加智能化能够根据应用的使用场景、设备的性能和用户的行为习惯动态调整缓存的大小、过期时间和清理策略以提供更高效的缓存服务。 11.3 与新兴技术的集成 Fresco 缓存模块可能会与新兴技术进行集成如人工智能、机器学习等。例如利用机器学习算法预测用户可能请求的图片提前将其缓存以提高图片的加载速度。 11.4 安全性增强 随着数据安全和隐私问题的日益重要Fresco 缓存模块可能会加强对缓存数据的加密和保护确保用户的图片数据在缓存过程中的安全性。 十二、总结 本文对 Android Fresco 框架的缓存模块进行了深入的源码级别分析。首先介绍了缓存模块的概述包括其作用、主要组件和架构。接着详细分析了内存缓存和磁盘缓存的实现类包括 LruMemoryCache 和 BufferedDiskCache以及它们的工作原理和使用示例。然后探讨了缓存键的生成策略、缓存策略的实现方式以及缓存模块的交互流程、性能优化和扩展性分析。最后介绍了缓存模块的错误处理与调试技巧以及未来的发展趋势。 通过对 Fresco 缓存模块的深入理解开发者可以更好地使用该框架优化应用的图片加载性能提高用户体验。同时也可以根据自己的需求对缓存模块进行定制和扩展以满足不同的业务场景。随着技术的不断发展Fresco 缓存模块也将不断演进和完善为 Android 开发者提供更强大的图片缓存功能。
http://www.zqtcl.cn/news/276259/

相关文章:

  • 视频类网站如何做缓存网页设计框架怎么写
  • wordpress建站访问提示不安全网页加速器哪个最好用
  • 网博士自助建站系统下载毕业设计代做网站唯一
  • 江西网站建设优化服务营销软文范例大全100字
  • 图片类网站怎样做高并发专业做旗袍花的网站是什么网站
  • 我要建网站需要什么专业网站制作全包
  • 网站开发合同印花税自定义手机网站建设
  • 营销型网站开发流程制作网站需要钱吗
  • 提供有经验的网站建设百度识图识别
  • html手机网站怎么做湖南关键词优化品牌推荐
  • 网站定制开发收费标准是多少易语言如何做浏网站
  • 网站怎么做实名认证新手怎么开婚庆公司
  • .net做网站用什么技术网站优化排名方案
  • 电商网站备案流程网站移动端优化的重点有哪些
  • 数据需求 网站建设做qq空间的网站
  • 微信网站游戏网络规划设计师可以挂证吗
  • 有个做特价的购物网站网站建设与维护题库及答案
  • 长沙网站优化价格创意设计师个人网站
  • 滨河网站建设南京免费发布信息网站
  • 蓝色系列的网站邓砚谷电子商务网站建设
  • 德阳市住房和城乡建设局网站首页一个服务器可以建多少个网站
  • 建一个电商网站多少钱一起做网店货源app
  • 做网站用lunx代理记账 营销型网站
  • 凡客做网站怎么样WordPress分类目录 前100篇
  • 腾讯wordpress 建站教程本地的上海网站建设公司
  • 深圳市南山区住房和建设局官方网站上海专业网站建设公司站霸网络
  • 建网站的8个详细步骤网站集约化建设讲话
  • 建设局哪个网站查证南京注册公司多少钱
  • 免费的网站制作郑州中森网站建设
  • 网站关键词搜不到了濮阳网络教育