【FastDev4Android框架开发】Android 数据缓存器ACache的详解和使用(四)

jerry Android 2015年11月26日 收藏

(一):写在前面的话
接着上一篇继续更新,上一篇文章已经把FastDev4Android项目列表下拉刷新组件(PullToRefreshListView)组件做了讲解和使用。今天项目更新是得数据缓存器(ACache)的详解和使用。
(二):功能介绍
2.1:基本介绍
ACache项目是我去年在Github上面发现的一个开源项目,首先感谢作者,感谢Github开源的力量。ACache是一个比较轻量级的数据缓存管理器(一个类ACache.java)解决问题,所以学习起来就非常简单,在中小型项目中可以较好的去使用。ACache使用采用手机包名路径下文件数据保存方式进行数据缓存,同时可以自定义设置数据缓存的路径,缓存的文件大小,以及缓存的文件数量以及相应的缓存过期时间。下面我们来看一下整个类中相应的方法和变量以及常量,这样对整个类有一个直观的了解。
这里写图片描述
这里写图片描述
查看以上各种方法,我们可以知道ACache给我们提供了文本数据,JSON格式数据,图片等信息缓存,当然我们也可以通过实际的项目情况,对该类进行其他格式数据的扩展。
2.2:ACache流程
ACache请求处理流程
这里写图片描述
(三):核心方法介绍
3.1:相关配置数据设置

  1. public static final int TIME_HOUR = 60 * 60; //缓存一个小时
  2. public static final int TIME_MINUTE = 60; //混存一分钟
  3. public static final int TIME_DAY = TIME_HOUR * 12; //缓存一个白天 12个小时
  4. private static final int MAX_SIZE = 1000 * 1000 * 50; // 50 mb
  5. private static final int MAX_COUNT = Integer.MAX_VALUE; // 不限制存放数据的数量
    • 1
    • 2
    • 3
    • 4
    • 5

以上可以自定义设置缓存时间,缓存文件大小和限制存放数据的数量等信息
3.2:静态获取ACache对象实现方法

  1. public static ACache get(Context ctx)
  2. public static ACache get(Context ctx, String cacheName)
  3. public static ACache get(File cacheDir)
  4. public static ACache get(Context ctx, long max_zise, int max_count)
    • 1
    • 2
    • 3
    • 4

使用者可以根据不同的参数分别获取ACache管理对象。
3.3:ACache对象创建方法:
①:对象获取

  1. public static ACache get(File cacheDir, long max_zise, int max_count) {
  2. ACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid());
  3. if (manager == null) {
  4. manager = new ACache(cacheDir, max_zise, max_count);
  5. mInstanceMap.put(cacheDir.getAbsolutePath() + myPid(), manager);
  6. }
  7. return manager;
  8. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

根据以上代码可以知道在创建ACache对象的时候,会先通过Map Cache缓存中去查找是否已经存在该对象,有直接返回,如果不存在那么进行创建对象实例(通过new ACache(xxx,xx,xx)),然后保存一份到Map缓存中。
②:对象创建

  1. private ACache(File cacheDir, long max_size, int max_count) {
  2. if (!cacheDir.exists() && !cacheDir.mkdirs()) {
  3. throw new RuntimeException("can't make dirs in "
  4. + cacheDir.getAbsolutePath());
  5. }
  6. mCache = new ACacheManager(cacheDir, max_size, max_count);
  7. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

以上代码可以得知最终我们使用的管理器就是ACacheManager实例,在这边进行缓存器的初始化(文件路径,缓存数量,缓存大小)以及数据最终保存和获取。那么最后我们来看一下整个ACacheManger的实现代码吧:

  1. public class ACacheManager {
  2. private final AtomicLong cacheSize;
  3. private final AtomicInteger cacheCount;
  4. private final long sizeLimit;
  5. private final int countLimit;
  6. private final Map<File, Long> lastUsageDates = Collections
  7. .synchronizedMap(new HashMap<File, Long>());
  8. protected File cacheDir;
  9. private ACacheManager(File cacheDir, long sizeLimit, int countLimit) {
  10. this.cacheDir = cacheDir;
  11. this.sizeLimit = sizeLimit;
  12. this.countLimit = countLimit;
  13. cacheSize = new AtomicLong();
  14. cacheCount = new AtomicInteger();
  15. calculateCacheSizeAndCacheCount();
  16. }
  17. /**
  18. * 计算 cacheSize和cacheCount
  19. */
  20. private void calculateCacheSizeAndCacheCount() {
  21. new Thread(new Runnable() {
  22. @Override
  23. public void run() {
  24. int size = 0;
  25. int count = 0;
  26. File[] cachedFiles = cacheDir.listFiles();
  27. if (cachedFiles != null) {
  28. for (File cachedFile : cachedFiles) {
  29. size += calculateSize(cachedFile);
  30. count += 1;
  31. lastUsageDates.put(cachedFile,
  32. cachedFile.lastModified());
  33. }
  34. cacheSize.set(size);
  35. cacheCount.set(count);
  36. }
  37. }
  38. }).start();
  39. }
  40. private void put(File file) {
  41. int curCacheCount = cacheCount.get();
  42. while (curCacheCount + 1 > countLimit) {
  43. long freedSize = removeNext();
  44. cacheSize.addAndGet(-freedSize);
  45. curCacheCount = cacheCount.addAndGet(-1);
  46. }
  47. cacheCount.addAndGet(1);
  48. long valueSize = calculateSize(file);
  49. long curCacheSize = cacheSize.get();
  50. while (curCacheSize + valueSize > sizeLimit) {
  51. long freedSize = removeNext();
  52. curCacheSize = cacheSize.addAndGet(-freedSize);
  53. }
  54. cacheSize.addAndGet(valueSize);
  55. Long currentTime = System.currentTimeMillis();
  56. file.setLastModified(currentTime);
  57. lastUsageDates.put(file, currentTime);
  58. }
  59. private File get(String key) {
  60. File file = newFile(key);
  61. Long currentTime = System.currentTimeMillis();
  62. file.setLastModified(currentTime);
  63. lastUsageDates.put(file, currentTime);
  64. return file;
  65. }
  66. private File newFile(String key) {
  67. return new File(cacheDir, key.hashCode() + "");
  68. }
  69. private boolean remove(String key) {
  70. File image = get(key);
  71. return image.delete();
  72. }
  73. private void clear() {
  74. lastUsageDates.clear();
  75. cacheSize.set(0);
  76. File[] files = cacheDir.listFiles();
  77. if (files != null) {
  78. for (File f : files) {
  79. f.delete();
  80. }
  81. }
  82. }
  83. /**
  84. * 移除旧的文件
  85. *
  86. * @return
  87. */
  88. private long removeNext() {
  89. if (lastUsageDates.isEmpty()) {
  90. return 0;
  91. }
  92. Long oldestUsage = null;
  93. File mostLongUsedFile = null;
  94. Set<Map.Entry<File, Long>> entries = lastUsageDates.entrySet();
  95. synchronized (lastUsageDates) {
  96. for (Map.Entry<File, Long> entry : entries) {
  97. if (mostLongUsedFile == null) {
  98. mostLongUsedFile = entry.getKey();
  99. oldestUsage = entry.getValue();
  100. } else {
  101. Long lastValueUsage = entry.getValue();
  102. if (lastValueUsage < oldestUsage) {
  103. oldestUsage = lastValueUsage;
  104. mostLongUsedFile = entry.getKey();
  105. }
  106. }
  107. }
  108. }
  109. long fileSize = calculateSize(mostLongUsedFile);
  110. if (mostLongUsedFile.delete()) {
  111. lastUsageDates.remove(mostLongUsedFile);
  112. }
  113. return fileSize;
  114. }
  115. private long calculateSize(File file) {
  116. return file.length();
  117. }
  118. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132

(四):使用介绍
我们在使用该工具的时候,很简单,获取对象实例,做put和get操作即可
ACache mACache=ACache.get(Contenxt) 默认获取方式,或者可以采用另外几个静态获取方法也可以,下面我们来看一下具体实现。

  1. private Button save_cache;
  2. private Button query_cache;
  3. private EditText edit_cache;
  4. private TextView tv_cache;
  5. private ACache mAcache;
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.sp_cache_layout);
  10. save_cache=(Button)this.findViewById(R.id.save_cache);
  11. query_cache=(Button)this.findViewById(R.id.query_cache);
  12. edit_cache=(EditText)this.findViewById(R.id.edit_cache);
  13. tv_cache=(TextView)this.findViewById(R.id.tv_cache);
  14. mAcache=ACache.get(this);
  15. //进行保存数据
  16. save_cache.setOnClickListener(new View.OnClickListener() {
  17. @Override
  18. public void onClick(View v) {
  19. String save_str = edit_cache.getText().toString().trim();
  20. mAcache.put(CacheConsts.DEMO_CACHE_KEY, save_str);
  21. showToastMsgShort("缓存成功...");
  22. }
  23. });
  24. //进行查询数据
  25. query_cache.setOnClickListener(new View.OnClickListener() {
  26. @Override
  27. public void onClick(View v) {
  28. String query_str=mAcache.getAsString(CacheConsts.DEMO_CACHE_KEY);
  29. tv_cache.setText(query_str);
  30. }
  31. });
  32. }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

运行结果如下:
这里写图片描述
到此为止我们今天ACache的讲解和使用结果,详细代码项目地址:
https://github.com/jiangqqlmj/FastDev4Android
同时欢迎大家star和fork整个开源快速开发框架项目~如果有什么意见和反馈,欢迎留言,必定第一时间回复。也欢迎有同样兴趣的童鞋加入到该项目中来,一起维护该项目。