从Jamendo加载到进入主页,Jamendo中所涉及的两种缓存都已经涉及到。

(一) RequestCache(服务器请求缓存)

从服务器上下载数据非常耗时,并且耗电。所以避免重复下载很有必要。Jamendo的RequestCache的原则是:保留最近10次(这个值可以自己设定)的网络请求。如果超过,清除最早的缓存内容。在调用Call获取服务器数据时,首先在RequestCache中查找,是否存在,如果不存在,向服务器请求,并将请求到的数据加入缓存中。很好理解的流程。RequestCache的代码如下:

 
  
  1. /* 
  2.  * Copyright (C) 2009 Teleca Poland Sp. z o.o. <android@teleca.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.  
  17. package com.teleca.jamendo.api.util; 
  18.  
  19. import java.util.Hashtable; 
  20. import java.util.LinkedList; 
  21.  
  22. /** 
  23.  * @author Lukasz Wisniewski 
  24.  */ 
  25. public class RequestCache { 
  26.      
  27.     // TODO cache lifeTime 
  28.      
  29.     private static int CACHE_LIMIT = 10;//保存最近十次的请求数据,key为url 
  30.      
  31.     @SuppressWarnings("unchecked"
  32.     private LinkedList history; 
  33.     private Hashtable<String, String> cache; 
  34.      
  35.     @SuppressWarnings("unchecked"
  36.     public RequestCache(){ 
  37.         history = new LinkedList(); 
  38.         cache = new Hashtable<String, String>(); 
  39.     } 
  40.      
  41.      
  42.     @SuppressWarnings("unchecked"
  43.     public void put(String url, String data){ 
  44.         history.add(url); 
  45.         // too much in the cache, we need to clear something 
  46.         if(history.size() > CACHE_LIMIT){ 
  47.             String old_url = (String) history.poll(); 
  48.             cache.remove(old_url); 
  49.         } 
  50.         cache.put(url, data); 
  51.     } 
  52.      
  53.     public String get(String url){ 
  54.         return cache.get(url); 
  55.     } 

Note:RequestCache使用的存储集合是HashTable,它不允许Null的key和value,并且是同步安全的。因为存储的数量较少,且是最耗时的操作,存储空值无意义,所以选用HashTable。

HashTable相关内容,参看:http://mikewang.blog.51cto.com/3826268/856865

(二) ImageCache缓存(图片缓存)

图片缓存的流程图如下:

 

代码如下:

 
  
  1. public class ImageCache extends WeakHashMap<String, Bitmap> { 
  2.  
  3.     private static final long serialVersionUID = 1L; 
  4.      
  5.     public boolean isCached(String url){ 
  6.         return containsKey(url) && get(url) != null
  7.     } 

显然,ImageCache继承了WeakHashmap。

WeakHashmap非常重要。我专门做了一个整理,相关内容我的博文:http://mikewang.blog.51cto.com/3826268/880775

当然,我们仍然对ImageCache缓存的取舍不是很清楚。回到RemoteImageView的setImageUrl方法。代码如下:

 
  
  1. public void setImageUrl(String url){ 
  2.          
  3. //      Log.d("img_url", "img_url is :" + url); 
  4.          
  5.         if (mUrl != null && mUrl.equals(url) && (mCurrentlyGrabbedUrl == null ||//1:url赋给全局变量mUrl,两者相等且都为空,但是未执行,所以mCurrentlyGrabbedUrl为空 
  6.                 (mCurrentlyGrabbedUrl != null && !mCurrentlyGrabbedUrl.equals(url)))) {//2:第n(n>1)次执行时,并未完成downloadTask 
  7.             mFailure++;          
  8.             if(mFailure > MAX_FAILURES){//超过指定重连次数 
  9.                 Log.e(JamendoApplication.TAG, "Failed to download "+url+", falling back to default p_w_picpath"); 
  10.                 loadDefaultImage(); 
  11.                 return
  12.             } 
  13.         } else { 
  14.             mUrl = url; 
  15.             mFailure = 0
  16.         } 
  17.  
  18.         updateCacheSize(); 
  19.          
  20.         if (mCacheSize>0 && (url.contains(ALBUMS) || url.contains(RADIOS))) {//只有两类路径图片需要缓存          
  21.             String fileName = convertUrlToFileName(url); 
  22.             String dir = getDirectory(fileName); 
  23.             Log.d("img_url""dir is :" + dir); 
  24.             String pathFileName = dir + "/" + fileName; 
  25.             Log.d("img_url""pathFileName is :" + pathFileName); 
  26.             Bitmap tbmp = BitmapFactory.decodeFile(pathFileName);//从指定文件保存路径解码处图片 
  27.             if (tbmp == null) { 
  28.                 Log.d(JamendoApplication.TAG, "Image is not present, try to download"); 
  29.                 try
  30.                     new DownloadTask().execute(url); 
  31.                 } catch (RejectedExecutionException e) { 
  32.                     // do nothing, just don't crash 
  33.                 } 
  34.             } else { 
  35.                 Log.i(JamendoApplication.TAG, "Loading album cover from file"); 
  36.                 this.setImageBitmap(tbmp); 
  37.                 updateFileTime(dir,fileName );               
  38.             } 
  39.              
  40.             removeAlbumCoversCache(dir, fileName);//对专辑图片的缓存处理:比较大120k 
  41.             removeRadioCoversCache(dir, fileName);//对广播图片的缓存处理:比较小8k 
  42.              
  43.         } 
  44.         else { 
  45.             Log.i(JamendoApplication.TAG, "File not cached supported" + url); 
  46.             ImageCache p_w_picpathCache = JamendoApplication.getInstance() 
  47.                     .getImageCache(); 
  48.             if (p_w_picpathCache.isCached(url)) {              
  49.                 this.setImageBitmap(p_w_picpathCache.get(url)); 
  50.             } else { 
  51.                 try { 
  52.                     Log.i(JamendoApplication.TAG, "Image is not present, try to download"); 
  53.                     new DownloadTask().execute(url); 
  54.                 } catch (RejectedExecutionException e) { 
  55.                     // do nothing, just don't crash 
  56.                 } 
  57.             } 
  58.         } 
  59.     } 

1. 对两类图片(AlbumCover和RadioCover)进行处理,打了log之后,AlbumCover的大小在120k左右,主要用在播放页面做背景。RadioCover的大小在8k左右,主要用来显示图标。对两者的处理也不同。大小是15倍左右的关系。代码如下:

 
  
  1. removeAlbumCoversCache(dir, fileName);//对专辑图片的缓存处理:比较大120k 
  2.             removeRadioCoversCache(dir, fileName);//对广播图片的缓存处理:比较小8k 

 

对AlbumCover,因为它的文件大小比较大,所以统计是否超出总的缓存容量时,以它的总大小计算就ok。代码如下:

 
  
  1. private void removeAlbumCoversCache(String dirPath, String filename) { 
  2.  
  3.         if (!filename.contains(ALBUM_COVER_MARKER)) { 
  4.             return
  5.         } 
  6.  
  7.         File dir = new File(dirPath); 
  8.         File[] files = dir.listFiles(); 
  9.  
  10.         if (files == null) { 
  11.             // possible sd card is not present/cant write 
  12.             return
  13.         } 
  14.  
  15.         int dirSize = 0
  16.  
  17.         for (int i = 0; i < files.length; i++) { 
  18.             if (files[i].getName().contains(ALBUM_COVER_MARKER)) {//计算出指定路径指定类型文件大小:只计算出大图片的大小,小的不用计算,简化 
  19.                 dirSize += files[i].length(); 
  20.             } 
  21.         } 
  22.          
  23.          
  24.         if (dirSize > mCacheSize * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) { 
  25.             int removeFactor = (int) ((0.4 * files.length) + 1);//移出缓存文件夹的四分之一文件 
  26.             Arrays.sort(files, new FileLastModifSort());//按照从老到新的顺序排列 
  27.             Log.i(JamendoApplication.TAG, "Clear some album covers cache files "); 
  28.             for (int i = 0; i < removeFactor; i++) {//移出选定数量的缓存文件(其中只删除占空间比较大的专辑图片,抓大舍小) 
  29.                 if (files[i].getName().contains(ALBUM_COVER_MARKER)) { 
  30.                     files[i].delete();               
  31.                 } 
  32.             } 
  33.         } 
  34.  
  35.     } 

对RadioCover,因为其所占空间很小,所以按照时间来清理。超过指定日期的文件就清理掉。清除缓存(下载)超过指定天数的文件,只保存最近45天内的文件。代码如下:

 
  
  1. private void removeRadioCoversCache(String dirPath, String filename) { 
  2.  
  3.         if (filename.contains(ALBUM_COVER_MARKER)) {//筛选出非专辑图片类图片 
  4.             return
  5.         } 
  6.  
  7.         File file = new File(dirPath, filename); 
  8.         if (file.lastModified() != 0 
  9.                 && System.currentTimeMillis() - file.lastModified() > mTimeDiff) {//清除缓存(下载)超过指定天数的文件,即所有的Radio类图片,只保存最近45天内的文件 
  10.                          
  11.             Log.i(JamendoApplication.TAG, "Clear some album or radio thumbnail cache files "); 
  12.             file.delete(); 
  13.         } 
  14.  
  15.     } 

2. 思考

这让做的好处是,抓住了真正耗时的关键,有的放矢。