fd0477b13f2d4582c7fb98a474e78febf21198f1.svn-base 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. package com.example.myapplication.utils;
  2. import android.annotation.TargetApi;
  3. import android.content.Context;
  4. import android.content.pm.PackageManager;
  5. import android.os.Build;
  6. import android.os.Environment;
  7. import android.os.StatFs;
  8. import android.text.TextUtils;
  9. import android.util.Log;
  10. import com.facebook.stetho.common.LogUtil;
  11. import com.example.myapplication.BuildConfig;
  12. import com.jakewharton.disklrucache.DiskLruCache;
  13. import java.io.File;
  14. import java.io.IOException;
  15. import java.io.InputStream;
  16. import java.io.OutputStream;
  17. import java.security.MessageDigest;
  18. import java.security.NoSuchAlgorithmException;
  19. import java.util.ArrayList;
  20. import java.util.List;
  21. import static android.os.Environment.MEDIA_MOUNTED;
  22. /**
  23. * 用本地的Disk文件来存储各种API数据的结果,在本地利用LRU算法进行文件缓存,缓存文件位于SD卡的<i>("/Android/data/[app_package_name]/cache")</i>目录下
  24. * <p/>
  25. */
  26. public class CacheUtils {
  27. private static final String TAG = "cunduoduo";
  28. // Default disk cache size in bytes
  29. private static final int DEFAULT_DISK_CACHE_SIZE = 1024 * 1024 * 100; // 100MB
  30. private static final String EXTERNAL_STORAGE_PERMISSION = "android.permission.WRITE_EXTERNAL_STORAGE";
  31. private static CacheUtils instance;
  32. private static final int DISK_CACHE_INDEX = 0;
  33. public static CacheUtils getInstance(Context context) {
  34. if (instance == null) {
  35. instance = new CacheUtils(context.getApplicationContext());
  36. }
  37. return instance;
  38. }
  39. private CacheUtils(Context context) {
  40. mCacheDir = getCacheDirectory(context);
  41. initDiskCache(context);
  42. }
  43. private DiskLruCache mDiskLruCache;
  44. private File mCacheDir;
  45. private final Object mDiskCacheLock = new Object();
  46. private boolean mDiskCacheStarting = true;
  47. /**
  48. * 初始化默认的文件Cache
  49. */
  50. public void initDiskCache(Context context) {
  51. // Set up disk cache
  52. synchronized (mDiskCacheLock) {
  53. if (mDiskLruCache == null || mDiskLruCache.isClosed()) {
  54. // if (getUsableSpace(mCacheDir) > DEFAULT_DISK_CACHE_SIZE) {
  55. try {
  56. mDiskLruCache = DiskLruCache.open(mCacheDir, PhoneUtil.getVersionCode(context), 1, DEFAULT_DISK_CACHE_SIZE);
  57. LogUtil.d("Disk cache initialized");
  58. } catch (final IOException e) {
  59. LogUtil.e("initDiskCache - " + e);
  60. }
  61. }
  62. // }
  63. mDiskCacheStarting = false;
  64. mDiskCacheLock.notifyAll();
  65. }
  66. }
  67. /**
  68. * 删除本地的文件Cache,全部清空并删除目录
  69. */
  70. public void clearCache(Context context) {
  71. synchronized (mDiskCacheLock) {
  72. mDiskCacheStarting = true;
  73. if (mDiskLruCache != null && !mDiskLruCache.isClosed()) {
  74. try {
  75. mDiskLruCache.delete();
  76. if (BuildConfig.DEBUG) {
  77. Log.d(TAG, "Disk cache cleared");
  78. }
  79. } catch (IOException e) {
  80. Log.e(TAG, "clearCache - " + e);
  81. }
  82. mDiskLruCache = null;
  83. initDiskCache(context);
  84. }
  85. }
  86. }
  87. /**
  88. * Flush文件缓存到文件里
  89. */
  90. public void flush() {
  91. synchronized (mDiskCacheLock) {
  92. if (mDiskLruCache != null) {
  93. try {
  94. mDiskLruCache.flush();
  95. if (BuildConfig.DEBUG) {
  96. Log.d(TAG, "Disk cache flushed");
  97. }
  98. } catch (IOException e) {
  99. Log.e(TAG, "flush - " + e);
  100. }
  101. }
  102. }
  103. }
  104. /**
  105. * 关闭文件缓存
  106. */
  107. public void close() {
  108. synchronized (mDiskCacheLock) {
  109. if (mDiskLruCache != null) {
  110. try {
  111. if (!mDiskLruCache.isClosed()) {
  112. mDiskLruCache.close();
  113. mDiskLruCache = null;
  114. // if (BuildConfig.DEBUG) {
  115. LogUtil.d("Disk cache closed");
  116. // }
  117. }
  118. } catch (IOException e) {
  119. LogUtil.e("close - " + e);
  120. }
  121. }
  122. }
  123. }
  124. /**
  125. * Check how much usable space is available at a given path.
  126. *
  127. * @param path The path to check
  128. * @return The space available in bytes
  129. */
  130. @TargetApi(Build.VERSION_CODES.GINGERBREAD)
  131. public static long getUsableSpace(File path) {
  132. final StatFs stats = new StatFs(path.getPath());
  133. return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();
  134. }
  135. /**
  136. * 将数据缓存到磁盘缓存中去,以参数data的MD5编码作为文件名,value为文件正文内容
  137. */
  138. public void set(final String data, final String value) {
  139. ThreadPool.getInstance().excute(new Runnable() {
  140. @Override
  141. public void run() {
  142. synchronized (mDiskCacheLock) {
  143. // Add to disk cache
  144. if (mDiskLruCache != null) {
  145. final String key = hashKeyForDisk(data);
  146. OutputStream out = null;
  147. try {
  148. final DiskLruCache.Editor editor = mDiskLruCache.edit(key);
  149. if (editor != null) {
  150. out = editor.newOutputStream(DISK_CACHE_INDEX);
  151. out.write(value.getBytes("UTF-8"));
  152. editor.commit();
  153. // out.close();
  154. }
  155. } catch (final IOException e) {
  156. Log.e(TAG, "addStringDataToCache - " + e);
  157. } catch (Exception e) {
  158. Log.e(TAG, "addStringDataToCache - " + e);
  159. } finally {
  160. try {
  161. if (out != null) {
  162. out.close();
  163. }
  164. } catch (IOException e) {
  165. LogUtil.e(e.getLocalizedMessage());
  166. }
  167. }
  168. }
  169. }
  170. }
  171. });
  172. }
  173. /**
  174. * 从文件缓存中获取数据
  175. */
  176. public String get(String data) {
  177. final String key = hashKeyForDisk(data);
  178. synchronized (mDiskCacheLock) {
  179. while (mDiskCacheStarting) {
  180. try {
  181. mDiskCacheLock.wait();
  182. } catch (InterruptedException e) {
  183. LogUtil.e(e.getLocalizedMessage());
  184. }
  185. }
  186. if (mDiskLruCache != null) {
  187. InputStream inputStream = null;
  188. try {
  189. final DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
  190. if (snapshot != null) {
  191. if (BuildConfig.DEBUG) {
  192. Log.d(TAG, "Disk cache hit");
  193. }
  194. inputStream = snapshot.getInputStream(DISK_CACHE_INDEX);
  195. if (inputStream != null) {
  196. byte[] buffer = new byte[inputStream.available()];
  197. inputStream.read(buffer);
  198. return new String(buffer, "UTF-8");
  199. // return EncodingUtils.getString(buffer, "UTF-8");
  200. }
  201. }
  202. } catch (final IOException e) {
  203. Log.e(TAG, "getFileDataFromCache - " + e);
  204. } finally {
  205. try {
  206. if (inputStream != null) {
  207. inputStream.close();
  208. }
  209. } catch (IOException e) {
  210. LogUtil.e(e.getLocalizedMessage());
  211. }
  212. }
  213. }
  214. return null;
  215. }
  216. }
  217. public <T> T getAs(String data, Class<T> dataType) {
  218. String value = get(data);
  219. if (!TextUtils.isEmpty(value)) {
  220. return JsonUtils.jsonObj(value, dataType);
  221. }
  222. return null;
  223. }
  224. public <T> List<T> getList(String data, Class<T> dataType) {
  225. String value = get(data);
  226. if (!TextUtils.isEmpty(value)) {
  227. return JsonUtils.jsonObjArray(value, dataType);
  228. }
  229. return new ArrayList<T>();
  230. }
  231. /**
  232. * 从文件缓存中删除数据
  233. */
  234. public void remove(String data) {
  235. final String key = hashKeyForDisk(data);
  236. synchronized (mDiskCacheLock) {
  237. while (mDiskCacheStarting) {
  238. try {
  239. mDiskCacheLock.wait();
  240. } catch (InterruptedException e) {
  241. LogUtil.e(e.getLocalizedMessage());
  242. }
  243. }
  244. if (mDiskLruCache != null) {
  245. try {
  246. mDiskLruCache.remove(key);
  247. } catch (IOException e) {
  248. LogUtil.e("removeFromCache - " + e);
  249. }
  250. }
  251. }
  252. }
  253. /**
  254. * Cache的key
  255. */
  256. public static String hashKeyForDisk(String key) {
  257. String cacheKey;
  258. try {
  259. final MessageDigest mDigest = MessageDigest.getInstance("MD5");
  260. mDigest.update(key.getBytes());
  261. cacheKey = bytesToHexString(mDigest.digest());
  262. } catch (NoSuchAlgorithmException e) {
  263. cacheKey = String.valueOf(key.hashCode());
  264. }
  265. return cacheKey;
  266. }
  267. private static String bytesToHexString(byte[] bytes) {
  268. // http://stackoverflow.com/questions/332079
  269. StringBuilder sb = new StringBuilder();
  270. for (int i = 0; i < bytes.length; i++) {
  271. String hex = Integer.toHexString(0xFF & bytes[i]);
  272. if (hex.length() == 1) {
  273. sb.append('0');
  274. }
  275. sb.append(hex);
  276. }
  277. return sb.toString();
  278. }
  279. /**
  280. * Returns application cache directory. Cache directory will be created on SD card
  281. * <i>("/Android/data/[app_package_name]/cache")</i> if card is mounted and app has appropriate
  282. * permission. Else - Android defines cache directory on device's file system.
  283. *
  284. * @param context Application context
  285. * @return Cache {@link File directory}
  286. */
  287. public static File getCacheDirectory(Context context) {
  288. File appCacheDir = null;
  289. if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) {
  290. appCacheDir = context.getExternalCacheDir();
  291. // appCacheDir = getExternalCacheDir(context);
  292. }
  293. if (appCacheDir == null) {
  294. appCacheDir = context.getCacheDir();
  295. }
  296. if (appCacheDir == null) {
  297. Log.w(TAG, "Can't define system cache directory! The app should be re-installed.");
  298. }
  299. return appCacheDir;
  300. }
  301. private static boolean hasExternalStoragePermission(Context context) {
  302. int perm = context.checkCallingOrSelfPermission(EXTERNAL_STORAGE_PERMISSION);
  303. return perm == PackageManager.PERMISSION_GRANTED;
  304. }
  305. }