上节课我们讲到普通应用缓存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 ) |
05 | BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(file)); |
06 | return bitmap.compress(CompressFormat.JPEG, 100 , out); |
07 | } catch (FileNotFoundException e) { |
最后附上Memory Cache和File Cache的具体代码,非常简单。
01 | public class MemoryCache { |
02 | private static final String TAG = "MemoryCache" ; |
05 | private WeakHashMap<String, Bitmap> cache = new WeakHashMap<String, Bitmap>(); |
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. |
12 | public Bitmap get(String key){ |
14 | return cache.get(key); |
19 | * Put a bitmap into cache with a unique key. |
20 | * @param key Should be unique. |
21 | * @param value A bitmap. |
23 | public void put(String key, Bitmap value){ |
24 | if (key != null && ! "" .equals(key) && value != null ){ |
25 | cache.put(key, value); |
27 | Log.d(TAG, "size of memory cache: " + cache.size()); |
32 | * clear the memory cache. |
01 | public class FileCache { |
03 | private static final String TAG = "MemoryCache" ; |
05 | private File cacheDir; |
09 | * @param context The context related to this cache. |
11 | public FileCache(Context context) { |
13 | if (android.os.Environment.getExternalStorageState() |
14 | .equals(android.os.Environment.MEDIA_MOUNTED)) |
16 | android.os.Environment.getExternalStorageDirectory(), |
19 | cacheDir = context.getCacheDir(); |
20 | if (!cacheDir.exists()) |
23 | Log.d(TAG, "cache dir: " + cacheDir.getAbsolutePath()); |
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. |
31 | public File getFile(String key) { |
32 | File f = new File(cacheDir, key); |
34 | Log.i(TAG, "the file you wanted exists " + f.getAbsolutePath()); |
37 | Log.w(TAG, "the file you wanted does not exists: " + f.getAbsolutePath()); |
44 | * Put a bitmap into cache with a unique key. |
45 | * @param key Should be unique. |
46 | * @param value A bitmap. |
48 | public void put(String key, Bitmap value){ |
49 | File f = new File(cacheDir, key); |
53 | } catch (IOException e) { |
57 | if (BitmapHelper.saveBitmap(f, value)) |
58 | Log.d(TAG, "Save file to sdcard successfully!" ); |
60 | Log.w(TAG, "Save file to sdcard failed!" ); |
65 | * Clear the cache directory on sdcard. |
68 | File[] files = cacheDir.listFiles(); |
没什么难的地方,直接贴代码。下节课我讲讲解如何使用异步任务下载数据,以及使用Controller操作Model,控制View的显示。