├── .gitignore ├── AsimpleCacheDemo ├── .classpath ├── .project ├── .settings │ ├── org.eclipse.core.resources.prefs │ └── org.eclipse.jdt.core.prefs ├── ASimpleCache │ └── org │ │ └── afinal │ │ └── simplecache │ │ └── ACache.java ├── AndroidManifest.xml ├── bin │ └── AndroidManifest.xml ├── gen │ └── com │ │ └── yangfuhai │ │ └── asimplecachedemo │ │ ├── BuildConfig.java │ │ └── R.java ├── ic_launcher-web.png ├── proguard-project.txt ├── project.properties ├── res │ ├── drawable │ │ ├── ic_launcher.png │ │ └── img_test.png │ ├── layout │ │ ├── activity_about.xml │ │ ├── activity_main.xml │ │ ├── activity_save_bitmap.xml │ │ ├── activity_save_drawable.xml │ │ ├── activity_save_file.xml │ │ ├── activity_save_jsonarray.xml │ │ ├── activity_save_jsonobject.xml │ │ ├── activity_save_object.xml │ │ └── activity_save_string.xml │ ├── menu │ │ └── activity_save_jsonarray.xml │ └── values │ │ ├── strings.xml │ │ └── styles.xml └── src │ └── com │ └── yangfuhai │ └── asimplecachedemo │ ├── AboutActivity.java │ ├── MainActivity.java │ ├── SaveBitmapActivity.java │ ├── SaveDrawableActivity.java │ ├── SaveJsonArrayActivity.java │ ├── SaveJsonObjectActivity.java │ ├── SaveMediaActivity.java │ ├── SaveObjectActivity.java │ ├── SaveStringActivity.java │ └── beans │ └── UserBean.java ├── LICENSE ├── README.md └── source └── src └── org └── afinal └── simplecache └── ACache.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Package Files # 4 | *.jar 5 | *.war 6 | *.ear 7 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | AsimpleCacheDemo 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.source=1.6 5 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/ASimpleCache/org/afinal/simplecache/ACache.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2012-2013, Michael Yang 杨福海 (www.yangfuhai.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.afinal.simplecache; 17 | 18 | import java.io.BufferedReader; 19 | import java.io.BufferedWriter; 20 | import java.io.ByteArrayInputStream; 21 | import java.io.ByteArrayOutputStream; 22 | import java.io.File; 23 | import java.io.FileInputStream; 24 | import java.io.FileNotFoundException; 25 | import java.io.FileOutputStream; 26 | import java.io.FileReader; 27 | import java.io.FileWriter; 28 | import java.io.IOException; 29 | import java.io.InputStream; 30 | import java.io.ObjectInputStream; 31 | import java.io.ObjectOutputStream; 32 | import java.io.OutputStream; 33 | import java.io.RandomAccessFile; 34 | import java.io.Serializable; 35 | import java.util.Collections; 36 | import java.util.HashMap; 37 | import java.util.Map; 38 | import java.util.Map.Entry; 39 | import java.util.Set; 40 | import java.util.concurrent.atomic.AtomicInteger; 41 | import java.util.concurrent.atomic.AtomicLong; 42 | 43 | import org.json.JSONArray; 44 | import org.json.JSONObject; 45 | 46 | import android.content.Context; 47 | import android.graphics.Bitmap; 48 | import android.graphics.BitmapFactory; 49 | import android.graphics.Canvas; 50 | import android.graphics.PixelFormat; 51 | import android.graphics.drawable.BitmapDrawable; 52 | import android.graphics.drawable.Drawable; 53 | 54 | /** 55 | * @author Michael Yang(www.yangfuhai.com) update at 2013.08.07 56 | */ 57 | public class ACache { 58 | public static final int TIME_HOUR = 60 * 60; 59 | public static final int TIME_DAY = TIME_HOUR * 24; 60 | private static final int MAX_SIZE = 1000 * 1000 * 50; // 50 mb 61 | private static final int MAX_COUNT = Integer.MAX_VALUE; // 不限制存放数据的数量 62 | private static Map mInstanceMap = new HashMap(); 63 | private ACacheManager mCache; 64 | 65 | public static ACache get(Context ctx) { 66 | return get(ctx, "ACache"); 67 | } 68 | 69 | public static ACache get(Context ctx, String cacheName) { 70 | File f = new File(ctx.getCacheDir(), cacheName); 71 | return get(f, MAX_SIZE, MAX_COUNT); 72 | } 73 | 74 | public static ACache get(File cacheDir) { 75 | return get(cacheDir, MAX_SIZE, MAX_COUNT); 76 | } 77 | 78 | public static ACache get(Context ctx, long max_zise, int max_count) { 79 | File f = new File(ctx.getCacheDir(), "ACache"); 80 | return get(f, max_zise, max_count); 81 | } 82 | 83 | public static ACache get(File cacheDir, long max_zise, int max_count) { 84 | ACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid()); 85 | if (manager == null) { 86 | manager = new ACache(cacheDir, max_zise, max_count); 87 | mInstanceMap.put(cacheDir.getAbsolutePath() + myPid(), manager); 88 | } 89 | return manager; 90 | } 91 | 92 | private static String myPid() { 93 | return "_" + android.os.Process.myPid(); 94 | } 95 | 96 | private ACache(File cacheDir, long max_size, int max_count) { 97 | if (!cacheDir.exists() && !cacheDir.mkdirs()) { 98 | throw new RuntimeException("can't make dirs in " + cacheDir.getAbsolutePath()); 99 | } 100 | mCache = new ACacheManager(cacheDir, max_size, max_count); 101 | } 102 | 103 | /** 104 | * Provides a means to save a cached file before the data are available. 105 | * Since writing about the file is complete, and its close method is called, 106 | * its contents will be registered in the cache. Example of use: 107 | * 108 | * ACache cache = new ACache(this) try { OutputStream stream = 109 | * cache.put("myFileName") stream.write("some bytes".getBytes()); // now 110 | * update cache! stream.close(); } catch(FileNotFoundException e){ 111 | * e.printStackTrace() } 112 | */ 113 | class xFileOutputStream extends FileOutputStream { 114 | File file; 115 | 116 | public xFileOutputStream(File file) throws FileNotFoundException { 117 | super(file); 118 | this.file = file; 119 | } 120 | 121 | public void close() throws IOException { 122 | super.close(); 123 | mCache.put(file); 124 | } 125 | } 126 | 127 | // ======================================= 128 | // ============ String数据 读写 ============== 129 | // ======================================= 130 | /** 131 | * 保存 String数据 到 缓存中 132 | * 133 | * @param key 134 | * 保存的key 135 | * @param value 136 | * 保存的String数据 137 | */ 138 | public void put(String key, String value) { 139 | File file = mCache.newFile(key); 140 | BufferedWriter out = null; 141 | try { 142 | out = new BufferedWriter(new FileWriter(file), 1024); 143 | out.write(value); 144 | } catch (IOException e) { 145 | e.printStackTrace(); 146 | } finally { 147 | if (out != null) { 148 | try { 149 | out.flush(); 150 | out.close(); 151 | } catch (IOException e) { 152 | e.printStackTrace(); 153 | } 154 | } 155 | mCache.put(file); 156 | } 157 | } 158 | 159 | /** 160 | * 保存 String数据 到 缓存中 161 | * 162 | * @param key 163 | * 保存的key 164 | * @param value 165 | * 保存的String数据 166 | * @param saveTime 167 | * 保存的时间,单位:秒 168 | */ 169 | public void put(String key, String value, int saveTime) { 170 | put(key, Utils.newStringWithDateInfo(saveTime, value)); 171 | } 172 | 173 | /** 174 | * 读取 String数据 175 | * 176 | * @param key 177 | * @return String 数据 178 | */ 179 | public String getAsString(String key) { 180 | File file = mCache.get(key); 181 | if (!file.exists()) 182 | return null; 183 | boolean removeFile = false; 184 | BufferedReader in = null; 185 | try { 186 | in = new BufferedReader(new FileReader(file)); 187 | String readString = ""; 188 | String currentLine; 189 | while ((currentLine = in.readLine()) != null) { 190 | readString += currentLine; 191 | } 192 | if (!Utils.isDue(readString)) { 193 | return Utils.clearDateInfo(readString); 194 | } else { 195 | removeFile = true; 196 | return null; 197 | } 198 | } catch (IOException e) { 199 | e.printStackTrace(); 200 | return null; 201 | } finally { 202 | if (in != null) { 203 | try { 204 | in.close(); 205 | } catch (IOException e) { 206 | e.printStackTrace(); 207 | } 208 | } 209 | if (removeFile) 210 | remove(key); 211 | } 212 | } 213 | 214 | // ======================================= 215 | // ============= JSONObject 数据 读写 ============== 216 | // ======================================= 217 | /** 218 | * 保存 JSONObject数据 到 缓存中 219 | * 220 | * @param key 221 | * 保存的key 222 | * @param value 223 | * 保存的JSON数据 224 | */ 225 | public void put(String key, JSONObject value) { 226 | put(key, value.toString()); 227 | } 228 | 229 | /** 230 | * 保存 JSONObject数据 到 缓存中 231 | * 232 | * @param key 233 | * 保存的key 234 | * @param value 235 | * 保存的JSONObject数据 236 | * @param saveTime 237 | * 保存的时间,单位:秒 238 | */ 239 | public void put(String key, JSONObject value, int saveTime) { 240 | put(key, value.toString(), saveTime); 241 | } 242 | 243 | /** 244 | * 读取JSONObject数据 245 | * 246 | * @param key 247 | * @return JSONObject数据 248 | */ 249 | public JSONObject getAsJSONObject(String key) { 250 | String JSONString = getAsString(key); 251 | try { 252 | JSONObject obj = new JSONObject(JSONString); 253 | return obj; 254 | } catch (Exception e) { 255 | e.printStackTrace(); 256 | return null; 257 | } 258 | } 259 | 260 | // ======================================= 261 | // ============ JSONArray 数据 读写 ============= 262 | // ======================================= 263 | /** 264 | * 保存 JSONArray数据 到 缓存中 265 | * 266 | * @param key 267 | * 保存的key 268 | * @param value 269 | * 保存的JSONArray数据 270 | */ 271 | public void put(String key, JSONArray value) { 272 | put(key, value.toString()); 273 | } 274 | 275 | /** 276 | * 保存 JSONArray数据 到 缓存中 277 | * 278 | * @param key 279 | * 保存的key 280 | * @param value 281 | * 保存的JSONArray数据 282 | * @param saveTime 283 | * 保存的时间,单位:秒 284 | */ 285 | public void put(String key, JSONArray value, int saveTime) { 286 | put(key, value.toString(), saveTime); 287 | } 288 | 289 | /** 290 | * 读取JSONArray数据 291 | * 292 | * @param key 293 | * @return JSONArray数据 294 | */ 295 | public JSONArray getAsJSONArray(String key) { 296 | String JSONString = getAsString(key); 297 | try { 298 | JSONArray obj = new JSONArray(JSONString); 299 | return obj; 300 | } catch (Exception e) { 301 | e.printStackTrace(); 302 | return null; 303 | } 304 | } 305 | 306 | // ======================================= 307 | // ============== byte 数据 读写 ============= 308 | // ======================================= 309 | /** 310 | * 保存 byte数据 到 缓存中 311 | * 312 | * @param key 313 | * 保存的key 314 | * @param value 315 | * 保存的数据 316 | */ 317 | public void put(String key, byte[] value) { 318 | File file = mCache.newFile(key); 319 | FileOutputStream out = null; 320 | try { 321 | out = new FileOutputStream(file); 322 | out.write(value); 323 | } catch (Exception e) { 324 | e.printStackTrace(); 325 | } finally { 326 | if (out != null) { 327 | try { 328 | out.flush(); 329 | out.close(); 330 | } catch (IOException e) { 331 | e.printStackTrace(); 332 | } 333 | } 334 | mCache.put(file); 335 | } 336 | } 337 | 338 | /** 339 | * Cache for a stream 340 | * 341 | * @param key 342 | * the file name. 343 | * @return OutputStream stream for writing data. 344 | * @throws FileNotFoundException 345 | * if the file can not be created. 346 | */ 347 | public OutputStream put(String key) throws FileNotFoundException { 348 | return new xFileOutputStream(mCache.newFile(key)); 349 | } 350 | 351 | /** 352 | * 353 | * @param key 354 | * the file name. 355 | * @return (InputStream or null) stream previously saved in cache. 356 | * @throws FileNotFoundException 357 | * if the file can not be opened 358 | */ 359 | public InputStream get(String key) throws FileNotFoundException { 360 | File file = mCache.get(key); 361 | if (!file.exists()) 362 | return null; 363 | return new FileInputStream(file); 364 | } 365 | 366 | /** 367 | * 保存 byte数据 到 缓存中 368 | * 369 | * @param key 370 | * 保存的key 371 | * @param value 372 | * 保存的数据 373 | * @param saveTime 374 | * 保存的时间,单位:秒 375 | */ 376 | public void put(String key, byte[] value, int saveTime) { 377 | put(key, Utils.newByteArrayWithDateInfo(saveTime, value)); 378 | } 379 | 380 | /** 381 | * 获取 byte 数据 382 | * 383 | * @param key 384 | * @return byte 数据 385 | */ 386 | public byte[] getAsBinary(String key) { 387 | RandomAccessFile RAFile = null; 388 | boolean removeFile = false; 389 | try { 390 | File file = mCache.get(key); 391 | if (!file.exists()) 392 | return null; 393 | RAFile = new RandomAccessFile(file, "r"); 394 | byte[] byteArray = new byte[(int) RAFile.length()]; 395 | RAFile.read(byteArray); 396 | if (!Utils.isDue(byteArray)) { 397 | return Utils.clearDateInfo(byteArray); 398 | } else { 399 | removeFile = true; 400 | return null; 401 | } 402 | } catch (Exception e) { 403 | e.printStackTrace(); 404 | return null; 405 | } finally { 406 | if (RAFile != null) { 407 | try { 408 | RAFile.close(); 409 | } catch (IOException e) { 410 | e.printStackTrace(); 411 | } 412 | } 413 | if (removeFile) 414 | remove(key); 415 | } 416 | } 417 | 418 | // ======================================= 419 | // ============= 序列化 数据 读写 =============== 420 | // ======================================= 421 | /** 422 | * 保存 Serializable数据 到 缓存中 423 | * 424 | * @param key 425 | * 保存的key 426 | * @param value 427 | * 保存的value 428 | */ 429 | public void put(String key, Serializable value) { 430 | put(key, value, -1); 431 | } 432 | 433 | /** 434 | * 保存 Serializable数据到 缓存中 435 | * 436 | * @param key 437 | * 保存的key 438 | * @param value 439 | * 保存的value 440 | * @param saveTime 441 | * 保存的时间,单位:秒 442 | */ 443 | public void put(String key, Serializable value, int saveTime) { 444 | ByteArrayOutputStream baos = null; 445 | ObjectOutputStream oos = null; 446 | try { 447 | baos = new ByteArrayOutputStream(); 448 | oos = new ObjectOutputStream(baos); 449 | oos.writeObject(value); 450 | byte[] data = baos.toByteArray(); 451 | if (saveTime != -1) { 452 | put(key, data, saveTime); 453 | } else { 454 | put(key, data); 455 | } 456 | } catch (Exception e) { 457 | e.printStackTrace(); 458 | } finally { 459 | try { 460 | oos.close(); 461 | } catch (IOException e) { 462 | } 463 | } 464 | } 465 | 466 | /** 467 | * 读取 Serializable数据 468 | * 469 | * @param key 470 | * @return Serializable 数据 471 | */ 472 | public Object getAsObject(String key) { 473 | byte[] data = getAsBinary(key); 474 | if (data != null) { 475 | ByteArrayInputStream bais = null; 476 | ObjectInputStream ois = null; 477 | try { 478 | bais = new ByteArrayInputStream(data); 479 | ois = new ObjectInputStream(bais); 480 | Object reObject = ois.readObject(); 481 | return reObject; 482 | } catch (Exception e) { 483 | e.printStackTrace(); 484 | return null; 485 | } finally { 486 | try { 487 | if (bais != null) 488 | bais.close(); 489 | } catch (IOException e) { 490 | e.printStackTrace(); 491 | } 492 | try { 493 | if (ois != null) 494 | ois.close(); 495 | } catch (IOException e) { 496 | e.printStackTrace(); 497 | } 498 | } 499 | } 500 | return null; 501 | 502 | } 503 | 504 | // ======================================= 505 | // ============== bitmap 数据 读写 ============= 506 | // ======================================= 507 | /** 508 | * 保存 bitmap 到 缓存中 509 | * 510 | * @param key 511 | * 保存的key 512 | * @param value 513 | * 保存的bitmap数据 514 | */ 515 | public void put(String key, Bitmap value) { 516 | put(key, Utils.Bitmap2Bytes(value)); 517 | } 518 | 519 | /** 520 | * 保存 bitmap 到 缓存中 521 | * 522 | * @param key 523 | * 保存的key 524 | * @param value 525 | * 保存的 bitmap 数据 526 | * @param saveTime 527 | * 保存的时间,单位:秒 528 | */ 529 | public void put(String key, Bitmap value, int saveTime) { 530 | put(key, Utils.Bitmap2Bytes(value), saveTime); 531 | } 532 | 533 | /** 534 | * 读取 bitmap 数据 535 | * 536 | * @param key 537 | * @return bitmap 数据 538 | */ 539 | public Bitmap getAsBitmap(String key) { 540 | if (getAsBinary(key) == null) { 541 | return null; 542 | } 543 | return Utils.Bytes2Bimap(getAsBinary(key)); 544 | } 545 | 546 | // ======================================= 547 | // ============= drawable 数据 读写 ============= 548 | // ======================================= 549 | /** 550 | * 保存 drawable 到 缓存中 551 | * 552 | * @param key 553 | * 保存的key 554 | * @param value 555 | * 保存的drawable数据 556 | */ 557 | public void put(String key, Drawable value) { 558 | put(key, Utils.drawable2Bitmap(value)); 559 | } 560 | 561 | /** 562 | * 保存 drawable 到 缓存中 563 | * 564 | * @param key 565 | * 保存的key 566 | * @param value 567 | * 保存的 drawable 数据 568 | * @param saveTime 569 | * 保存的时间,单位:秒 570 | */ 571 | public void put(String key, Drawable value, int saveTime) { 572 | put(key, Utils.drawable2Bitmap(value), saveTime); 573 | } 574 | 575 | /** 576 | * 读取 Drawable 数据 577 | * 578 | * @param key 579 | * @return Drawable 数据 580 | */ 581 | public Drawable getAsDrawable(String key) { 582 | if (getAsBinary(key) == null) { 583 | return null; 584 | } 585 | return Utils.bitmap2Drawable(Utils.Bytes2Bimap(getAsBinary(key))); 586 | } 587 | 588 | /** 589 | * 获取缓存文件 590 | * 591 | * @param key 592 | * @return value 缓存的文件 593 | */ 594 | public File file(String key) { 595 | File f = mCache.newFile(key); 596 | if (f.exists()) 597 | return f; 598 | return null; 599 | } 600 | 601 | /** 602 | * 移除某个key 603 | * 604 | * @param key 605 | * @return 是否移除成功 606 | */ 607 | public boolean remove(String key) { 608 | return mCache.remove(key); 609 | } 610 | 611 | /** 612 | * 清除所有数据 613 | */ 614 | public void clear() { 615 | mCache.clear(); 616 | } 617 | 618 | /** 619 | * @title 缓存管理器 620 | * @author 杨福海(michael) www.yangfuhai.com 621 | * @version 1.0 622 | */ 623 | public class ACacheManager { 624 | private final AtomicLong cacheSize; 625 | private final AtomicInteger cacheCount; 626 | private final long sizeLimit; 627 | private final int countLimit; 628 | private final Map lastUsageDates = Collections.synchronizedMap(new HashMap()); 629 | protected File cacheDir; 630 | 631 | private ACacheManager(File cacheDir, long sizeLimit, int countLimit) { 632 | this.cacheDir = cacheDir; 633 | this.sizeLimit = sizeLimit; 634 | this.countLimit = countLimit; 635 | cacheSize = new AtomicLong(); 636 | cacheCount = new AtomicInteger(); 637 | calculateCacheSizeAndCacheCount(); 638 | } 639 | 640 | /** 641 | * 计算 cacheSize和cacheCount 642 | */ 643 | private void calculateCacheSizeAndCacheCount() { 644 | new Thread(new Runnable() { 645 | @Override 646 | public void run() { 647 | int size = 0; 648 | int count = 0; 649 | File[] cachedFiles = cacheDir.listFiles(); 650 | if (cachedFiles != null) { 651 | for (File cachedFile : cachedFiles) { 652 | size += calculateSize(cachedFile); 653 | count += 1; 654 | lastUsageDates.put(cachedFile, cachedFile.lastModified()); 655 | } 656 | cacheSize.set(size); 657 | cacheCount.set(count); 658 | } 659 | } 660 | }).start(); 661 | } 662 | 663 | private void put(File file) { 664 | int curCacheCount = cacheCount.get(); 665 | while (curCacheCount + 1 > countLimit) { 666 | long freedSize = removeNext(); 667 | cacheSize.addAndGet(-freedSize); 668 | 669 | curCacheCount = cacheCount.addAndGet(-1); 670 | } 671 | cacheCount.addAndGet(1); 672 | 673 | long valueSize = calculateSize(file); 674 | long curCacheSize = cacheSize.get(); 675 | while (curCacheSize + valueSize > sizeLimit) { 676 | long freedSize = removeNext(); 677 | curCacheSize = cacheSize.addAndGet(-freedSize); 678 | } 679 | cacheSize.addAndGet(valueSize); 680 | 681 | Long currentTime = System.currentTimeMillis(); 682 | file.setLastModified(currentTime); 683 | lastUsageDates.put(file, currentTime); 684 | } 685 | 686 | private File get(String key) { 687 | File file = newFile(key); 688 | Long currentTime = System.currentTimeMillis(); 689 | file.setLastModified(currentTime); 690 | lastUsageDates.put(file, currentTime); 691 | 692 | return file; 693 | } 694 | 695 | private File newFile(String key) { 696 | return new File(cacheDir, key.hashCode() + ""); 697 | } 698 | 699 | private boolean remove(String key) { 700 | File image = get(key); 701 | return image.delete(); 702 | } 703 | 704 | private void clear() { 705 | lastUsageDates.clear(); 706 | cacheSize.set(0); 707 | File[] files = cacheDir.listFiles(); 708 | if (files != null) { 709 | for (File f : files) { 710 | f.delete(); 711 | } 712 | } 713 | } 714 | 715 | /** 716 | * 移除旧的文件 717 | * 718 | * @return 719 | */ 720 | private long removeNext() { 721 | if (lastUsageDates.isEmpty()) { 722 | return 0; 723 | } 724 | 725 | Long oldestUsage = null; 726 | File mostLongUsedFile = null; 727 | Set> entries = lastUsageDates.entrySet(); 728 | synchronized (lastUsageDates) { 729 | for (Entry entry : entries) { 730 | if (mostLongUsedFile == null) { 731 | mostLongUsedFile = entry.getKey(); 732 | oldestUsage = entry.getValue(); 733 | } else { 734 | Long lastValueUsage = entry.getValue(); 735 | if (lastValueUsage < oldestUsage) { 736 | oldestUsage = lastValueUsage; 737 | mostLongUsedFile = entry.getKey(); 738 | } 739 | } 740 | } 741 | } 742 | 743 | long fileSize = calculateSize(mostLongUsedFile); 744 | if (mostLongUsedFile.delete()) { 745 | lastUsageDates.remove(mostLongUsedFile); 746 | } 747 | return fileSize; 748 | } 749 | 750 | private long calculateSize(File file) { 751 | return file.length(); 752 | } 753 | } 754 | 755 | /** 756 | * @title 时间计算工具类 757 | * @author 杨福海(michael) www.yangfuhai.com 758 | * @version 1.0 759 | */ 760 | private static class Utils { 761 | 762 | /** 763 | * 判断缓存的String数据是否到期 764 | * 765 | * @param str 766 | * @return true:到期了 false:还没有到期 767 | */ 768 | private static boolean isDue(String str) { 769 | return isDue(str.getBytes()); 770 | } 771 | 772 | /** 773 | * 判断缓存的byte数据是否到期 774 | * 775 | * @param data 776 | * @return true:到期了 false:还没有到期 777 | */ 778 | private static boolean isDue(byte[] data) { 779 | String[] strs = getDateInfoFromDate(data); 780 | if (strs != null && strs.length == 2) { 781 | String saveTimeStr = strs[0]; 782 | while (saveTimeStr.startsWith("0")) { 783 | saveTimeStr = saveTimeStr.substring(1, saveTimeStr.length()); 784 | } 785 | long saveTime = Long.valueOf(saveTimeStr); 786 | long deleteAfter = Long.valueOf(strs[1]); 787 | if (System.currentTimeMillis() > saveTime + deleteAfter * 1000) { 788 | return true; 789 | } 790 | } 791 | return false; 792 | } 793 | 794 | private static String newStringWithDateInfo(int second, String strInfo) { 795 | return createDateInfo(second) + strInfo; 796 | } 797 | 798 | private static byte[] newByteArrayWithDateInfo(int second, byte[] data2) { 799 | byte[] data1 = createDateInfo(second).getBytes(); 800 | byte[] retdata = new byte[data1.length + data2.length]; 801 | System.arraycopy(data1, 0, retdata, 0, data1.length); 802 | System.arraycopy(data2, 0, retdata, data1.length, data2.length); 803 | return retdata; 804 | } 805 | 806 | private static String clearDateInfo(String strInfo) { 807 | if (strInfo != null && hasDateInfo(strInfo.getBytes())) { 808 | strInfo = strInfo.substring(strInfo.indexOf(mSeparator) + 1, strInfo.length()); 809 | } 810 | return strInfo; 811 | } 812 | 813 | private static byte[] clearDateInfo(byte[] data) { 814 | if (hasDateInfo(data)) { 815 | return copyOfRange(data, indexOf(data, mSeparator) + 1, data.length); 816 | } 817 | return data; 818 | } 819 | 820 | private static boolean hasDateInfo(byte[] data) { 821 | return data != null && data.length > 15 && data[13] == '-' && indexOf(data, mSeparator) > 14; 822 | } 823 | 824 | private static String[] getDateInfoFromDate(byte[] data) { 825 | if (hasDateInfo(data)) { 826 | String saveDate = new String(copyOfRange(data, 0, 13)); 827 | String deleteAfter = new String(copyOfRange(data, 14, indexOf(data, mSeparator))); 828 | return new String[] { saveDate, deleteAfter }; 829 | } 830 | return null; 831 | } 832 | 833 | private static int indexOf(byte[] data, char c) { 834 | for (int i = 0; i < data.length; i++) { 835 | if (data[i] == c) { 836 | return i; 837 | } 838 | } 839 | return -1; 840 | } 841 | 842 | private static byte[] copyOfRange(byte[] original, int from, int to) { 843 | int newLength = to - from; 844 | if (newLength < 0) 845 | throw new IllegalArgumentException(from + " > " + to); 846 | byte[] copy = new byte[newLength]; 847 | System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); 848 | return copy; 849 | } 850 | 851 | private static final char mSeparator = ' '; 852 | 853 | private static String createDateInfo(int second) { 854 | String currentTime = System.currentTimeMillis() + ""; 855 | while (currentTime.length() < 13) { 856 | currentTime = "0" + currentTime; 857 | } 858 | return currentTime + "-" + second + mSeparator; 859 | } 860 | 861 | /* 862 | * Bitmap → byte[] 863 | */ 864 | private static byte[] Bitmap2Bytes(Bitmap bm) { 865 | if (bm == null) { 866 | return null; 867 | } 868 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 869 | bm.compress(Bitmap.CompressFormat.PNG, 100, baos); 870 | return baos.toByteArray(); 871 | } 872 | 873 | /* 874 | * byte[] → Bitmap 875 | */ 876 | private static Bitmap Bytes2Bimap(byte[] b) { 877 | if (b.length == 0) { 878 | return null; 879 | } 880 | return BitmapFactory.decodeByteArray(b, 0, b.length); 881 | } 882 | 883 | /* 884 | * Drawable → Bitmap 885 | */ 886 | private static Bitmap drawable2Bitmap(Drawable drawable) { 887 | if (drawable == null) { 888 | return null; 889 | } 890 | // 取 drawable 的长宽 891 | int w = drawable.getIntrinsicWidth(); 892 | int h = drawable.getIntrinsicHeight(); 893 | // 取 drawable 的颜色格式 894 | Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 895 | // 建立对应 bitmap 896 | Bitmap bitmap = Bitmap.createBitmap(w, h, config); 897 | // 建立对应 bitmap 的画布 898 | Canvas canvas = new Canvas(bitmap); 899 | drawable.setBounds(0, 0, w, h); 900 | // 把 drawable 内容画到画布中 901 | drawable.draw(canvas); 902 | return bitmap; 903 | } 904 | 905 | /* 906 | * Bitmap → Drawable 907 | */ 908 | @SuppressWarnings("deprecation") 909 | private static Drawable bitmap2Drawable(Bitmap bm) { 910 | if (bm == null) { 911 | return null; 912 | } 913 | BitmapDrawable bd=new BitmapDrawable(bm); 914 | bd.setTargetDensity(bm.getDensity()); 915 | return new BitmapDrawable(bm); 916 | } 917 | } 918 | 919 | } 920 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 12 | 13 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 37 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/bin/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 12 | 13 | 18 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 37 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/gen/com/yangfuhai/asimplecachedemo/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /** Automatically generated file. DO NOT MODIFY */ 2 | package com.yangfuhai.asimplecachedemo; 3 | 4 | public final class BuildConfig { 5 | public final static boolean DEBUG = true; 6 | } -------------------------------------------------------------------------------- /AsimpleCacheDemo/gen/com/yangfuhai/asimplecachedemo/R.java: -------------------------------------------------------------------------------- 1 | /* AUTO-GENERATED FILE. DO NOT MODIFY. 2 | * 3 | * This class was automatically generated by the 4 | * aapt tool from the resource data it found. It 5 | * should not be modified by hand. 6 | */ 7 | 8 | package com.yangfuhai.asimplecachedemo; 9 | 10 | public final class R { 11 | public static final class attr { 12 | } 13 | public static final class drawable { 14 | public static final int ic_launcher=0x7f020000; 15 | public static final int img_test=0x7f020001; 16 | } 17 | public static final class id { 18 | public static final int btn_about=0x7f070008; 19 | public static final int btn_save_bitmap=0x7f070004; 20 | public static final int btn_save_drawable=0x7f070006; 21 | public static final int btn_save_file=0x7f070005; 22 | public static final int btn_save_jsonarray=0x7f070003; 23 | public static final int btn_save_jsonobject=0x7f070002; 24 | public static final int btn_save_object=0x7f070007; 25 | public static final int btn_save_string=0x7f070001; 26 | public static final int et_string_input=0x7f070012; 27 | public static final int iv_bitmap_res=0x7f070009; 28 | public static final int iv_drawable_res=0x7f07000a; 29 | public static final int menu_settings=0x7f070014; 30 | public static final int text=0x7f07000b; 31 | public static final int textView1=0x7f070000; 32 | public static final int tv_jsonarray_original=0x7f07000c; 33 | public static final int tv_jsonarray_res=0x7f07000d; 34 | public static final int tv_jsonobject_original=0x7f07000e; 35 | public static final int tv_jsonobject_res=0x7f07000f; 36 | public static final int tv_object_original=0x7f070010; 37 | public static final int tv_object_res=0x7f070011; 38 | public static final int tv_string_res=0x7f070013; 39 | } 40 | public static final class layout { 41 | public static final int activity_about=0x7f030000; 42 | public static final int activity_main=0x7f030001; 43 | public static final int activity_save_bitmap=0x7f030002; 44 | public static final int activity_save_drawable=0x7f030003; 45 | public static final int activity_save_file=0x7f030004; 46 | public static final int activity_save_jsonarray=0x7f030005; 47 | public static final int activity_save_jsonobject=0x7f030006; 48 | public static final int activity_save_object=0x7f030007; 49 | public static final int activity_save_string=0x7f030008; 50 | } 51 | public static final class menu { 52 | public static final int activity_save_jsonarray=0x7f060000; 53 | } 54 | public static final class string { 55 | public static final int app_name=0x7f040000; 56 | public static final int hello_world=0x7f040001; 57 | public static final int menu_settings=0x7f040002; 58 | public static final int title_activity_save_drawable=0x7f040003; 59 | public static final int title_activity_save_json_array=0x7f040004; 60 | } 61 | public static final class style { 62 | /** 63 | Base application theme, dependent on API level. This theme is replaced 64 | by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 65 | 66 | 67 | Theme customizations available in newer API levels can go in 68 | res/values-vXX/styles.xml, while customizations related to 69 | backward-compatibility can go here. 70 | 71 | */ 72 | public static final int AppBaseTheme=0x7f050000; 73 | /** Application theme. 74 | All customizations that are NOT specific to a particular API-level can go here. 75 | */ 76 | public static final int AppTheme=0x7f050001; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/ASimpleCache/7935b04751aa57299cfb8b89e5b1e12a2d96e7cb/AsimpleCacheDemo/ic_launcher-web.png -------------------------------------------------------------------------------- /AsimpleCacheDemo/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/ASimpleCache/7935b04751aa57299cfb8b89e5b1e12a2d96e7cb/AsimpleCacheDemo/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /AsimpleCacheDemo/res/drawable/img_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangfuhai/ASimpleCache/7935b04751aa57299cfb8b89e5b1e12a2d96e7cb/AsimpleCacheDemo/res/drawable/img_test.png -------------------------------------------------------------------------------- /AsimpleCacheDemo/res/layout/activity_about.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | -------------------------------------------------------------------------------- /AsimpleCacheDemo/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 |