​上节课​我们讲到普通应用缓存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的显示。