【構建Android快取模組】(二)Memory Cache & File Cache

yangxi_001發表於2013-11-27

 節課我們講到普通應用快取Bitmap的實現分析,根據MVC的實現原理,我將這個簡單的快取實現單獨寫成一個模組,這樣可以方便以後的使用,對於任意的需求,都屬於一個可插拔式的功能。

    之前提到,這個快取模組主要有兩個子部件:

    Memory Cache:記憶體快取的存取速度非常驚人,遠遠快於檔案讀取,如果沒有記憶體限制,當然首選這種方式。遺憾的是我們有著16M的限制(當然大多數裝置限制要高於Android官方說的這個數字),這也正是大Bitmap容易引起OOM的原因。Memory Cache將使用WeakHashMap作為快取的中樞,當程式記憶體告急時,它會主動清理部分弱引用(因此,當引用指向為null,我們必須轉向硬碟快取讀取資料,如果硬碟也沒有,那還是重新下載吧)。

    能力越大,責任越大?人家只是跑得快了點兒,總得讓人家休息,我們一定不希望讓記憶體成為第一位跑完馬拉松的Pheidippides,一次以後就掛了吧?作為精打細算的猿媛,我們只能將有限的記憶體分配給Memory Cache將更繁重的任務託付給任勞任怨的SDCard

    File Cache:硬碟讀取速度當然不如記憶體,但是為了珍惜寶貴的流量,不讓你的使用者在月底沒有流量時嚎叫著要刪掉你開發的“流量殺手”,最好是避免重複下載。在第一次下載以後,將資料儲存在本地即可。

    檔案讀寫的技術並不是很新穎的技術,Java Core那點兒就夠你用了。不過要記得我們可是將Bitmap寫入檔案啊,怎麼寫入呢?不用著急,Android的Bitmap本身就具備將資料寫入OutputStream的能力。我將這些額外的方法寫在一個幫助類中:BitmapHelper

01 public static boolean saveBitmap(File file, Bitmap bitmap){
02     if(file == null || bitmap == null)
03         return false;
04     try {
05         BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
06         return bitmap.compress(CompressFormat.JPEG, 100, out);
07     catch (FileNotFoundException e) {
08         e.printStackTrace();
09         return false;
10     }
11 }
    最後附上Memory Cache和File Cache的具體程式碼,非常簡單。


01 public class MemoryCache {
02     private static final String TAG = "MemoryCache";
03      
04     //WeakReference Map: key=string, value=Bitmap
05     private WeakHashMap<String, Bitmap> cache = new WeakHashMap<String, Bitmap>();
06      
07     /**
08      * Search the memory cache by a unique key.
09      * @param key Should be unique.
10      * @return The Bitmap object in memory cache corresponding to specific key.
11      * */
12     public Bitmap get(String key){
13         if(key != null)
14             return cache.get(key);
15         return null;
16     }
17      
18     /**
19      * Put a bitmap into cache with a unique key.
20      * @param key Should be unique.
21      * @param value A bitmap.
22      * */
23     public void put(String key, Bitmap value){
24         if(key != null && !"".equals(key) && value != null){
25             cache.put(key, value);
26             //Log.i(TAG, "cache bitmap: " + key);
27             Log.d(TAG, "size of memory cache: " + cache.size());
28         }
29     }
30  
31     /**
32      * clear the memory cache.
33      * */
34     public void clear() {
35         cache.clear();
36     }
37 }
01 public class FileCache {
02      
03     private static final String TAG = "MemoryCache";
04      
05     private File cacheDir;  //the directory to save images
06  
07     /**
08      * Constructor
09      * @param context The context related to this cache.
10      * */
11     public FileCache(Context context) {
12         // Find the directory to save cached images
13         if (android.os.Environment.getExternalStorageState()
14                 .equals(android.os.Environment.MEDIA_MOUNTED))
15             cacheDir = new File(
16                     android.os.Environment.getExternalStorageDirectory(),
17                     Config.CACHE_DIR);
18         else
19             cacheDir = context.getCacheDir();
20         if (!cacheDir.exists())
21             cacheDir.mkdirs();
22          
23         Log.d(TAG, "cache dir: " + cacheDir.getAbsolutePath());
24     }
25  
26     /**
27      * Search the specific image file with a unique key.
28      * @param key Should be unique.
29      * @return Returns the image file corresponding to the key.
30      * */
31     public File getFile(String key) {
32         File f = new File(cacheDir, key);
33         if (f.exists()){
34             Log.i(TAG, "the file you wanted exists " + f.getAbsolutePath());
35             return f;
36         }else{
37             Log.w(TAG, "the file you wanted does not exists: " + f.getAbsolutePath());
38         }
39  
40         return null;
41     }
42  
43     /**
44      * Put a bitmap into cache with a unique key.
45      * @param key Should be unique.
46      * @param value A bitmap.
47      * */
48     public void put(String key, Bitmap value){
49         File f = new File(cacheDir, key);
50         if(!f.exists())
51             try {
52                 f.createNewFile();
53             catch (IOException e) {
54                 e.printStackTrace();
55             }
56         //Use the util's function to save the bitmap.
57         if(BitmapHelper.saveBitmap(f, value))
58             Log.d(TAG, "Save file to sdcard successfully!");
59         else
60             Log.w(TAG, "Save file to sdcard failed!");
61          
62     }
63      
64     /**
65      * Clear the cache directory on sdcard.
66      * */
67     public void clear() {
68         File[] files = cacheDir.listFiles();
69         for (File f : files)
70             f.delete();
71     }
72 }
    沒什麼難的地方,直接貼程式碼。下節課我講講解如何使用非同步任務下載資料,以及使用Controller操作Model,控制View的顯示。 

相關文章