Android學習系列(27)--App緩存管理


不管大型或小型應用,靈活的緩存能夠說不只大大減輕了服務器的壓力,並且由於更快速的用戶體驗而方便了用戶。
Android的apk能夠說是做爲小型應用,其中99%的應用並非須要實時更新的,並且詬病於蝸牛般的移動網速,與服務器的數據交互是能少則少,這樣用戶體驗才更好,這也是咱們有時捨棄webview而採用json傳輸數據的緣由之一。 
採用緩存,能夠進一步大大緩解數據交互的壓力,特此,咱們簡略列舉一下緩存管理的適用環境:
1. 提供網絡服務的應用
2. 數據更新不須要實時更新,可是哪怕是3-5分鐘的延遲也是能夠採用緩存機制。 
3. 緩存的過時時間是能夠接受的(不會由於緩存帶來的好處,致使某些數據由於更新不及時而影響產品的形象等)
帶來的好處:
1. 服務器的壓力大大減少
2. 客戶端的響應速度大大變快(用戶體驗)
3. 客戶端的數據加載出錯狀況大大較少,大大提升了應有的穩定性(用戶體驗)
4. 必定程度上能夠支持離線瀏覽(或者說爲離線瀏覽提供了技術支持)java

1、緩存管理的方法
這裏的緩存管理的原理很簡:經過時間的設置來判斷是否讀取緩存仍是從新下載。
裏面會有一些細節的處理,後面會詳細闡述。
基於這個原理,目前鄙人見過的兩種比較常見的緩存管理方法是:數據庫法和文件法。android

2、數據庫法緩存管理
這種方法是在下載完數據文件後,把文件的相關信息如url,路經,下載時間,過時時間等存放到數據庫,下次下載的時候根據url先從數據庫中查詢,若是查詢到當前時間並未過時,就根據路徑讀取本地文件,從而實現緩存的效果。
從實現上咱們能夠看到這種方法能夠靈活存放文件的屬性,進而提供了很大的擴展性,能夠爲其它的功能提供必定的支持;
從操做上須要建立數據庫,每次查詢數據庫,若是過時還須要更新數據庫,清理緩存的時候還須要刪除數據庫數據,稍顯麻煩,而數據庫操做不當又容易出現一系列的性能,ANR問題,實現的時候要謹慎,具體做的話,但也只是增長一個工具類或方法的事情。
還有一個問題,緩存的數據庫是存放在/data/data/<package>/databases/目錄下,是佔用內存空間的,若是緩存累計,容易浪費內存,須要及時清理緩存。
固然這種方法從目前一些應用的實用上看,我沒有發現什麼問題。
本文我側重強調第二種方法,第一種方法的實現,就此掠過。 web

3、文件法緩存管理
這種方法,使用File.lastModified()方法獲得文件的最後修改時間,與當前時間判斷是否過時,從而實現緩存效果。
實現上只能使用這一個屬性,沒有爲其它的功能提供技術支持的可能。
操做上卻是簡單,比較時間便可。自己處理也不容易帶來其它問題,代價低廉。數據庫

4、文件法緩存管理的兩點說明
1. 不一樣類型的文件的緩存時間不同。
籠統的說,不變文件的緩存時間是永久,變化文件的緩存時間是最大忍受不變時間。
說白點,圖片文件內容是不變的,直到清理,咱們是能夠永遠讀取緩存的。
配置文件內容是可能更新的,須要設置一個可接受的緩存時間。
2. 不一樣環境下的緩存時間標準不同。
無網絡環境下,咱們只能讀取緩存文件,哪怕緩存早就過時。
WiFi網絡環境下,緩存時間能夠設置短一點,一是網速較快,而是流量不要錢。
移動數據流量環境下,緩存時間能夠設置長一點,節省流量,就是節省金錢,並且用戶體驗也更好。
舉個例子吧,最近本人在作的一個應用在wifi環境下的緩存時間設置爲5分鐘,移動數據流量下的緩存時間設置爲1小時。
這個時間根據本身的實際狀況來設置:數據的更新頻率,數據的重要性等。json

5、什麼時候刷新
開發者一方面但願儘可能讀取緩存,用戶一方面但願實時刷新,可是響應速度越快越好,流量消耗越少越好,是一個矛盾。
其實什麼時候刷新我也不知道,這裏我提供兩點建議:
1. 數據的最長多長時間不變,對應用無大的影響。
好比,你的數據更新時間爲1天,則緩存時間設置爲4~8小時比較合適,一天他總會看到更新,若是你以爲你是資訊類應用,再減小,2~4小時,若是你以爲數據比較重要或者比較受歡迎,用戶會常常把玩,再減小,1~2小時,依次類推。
爲了保險起見,你可能須要毫無理由的再次縮減一下。
2. 提供刷新按鈕。
上面說的保險起見不必定保險,最保險的方法使在相關界面提供一個刷新按鈕,爲緩存,爲加載失敗提供一次從新來過的機會,有了這個刷新按鈕,咱們的心也才真的放下來。瀏覽器

6、文件緩存法的具體實現
針對配置文件的緩存,我新建了一個類ConfigCache:緩存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import  java.io.File;
import  java.io.IOException;
 
import  android.util.Log;
 
import  com.tianxia.app.floworld.AppApplication;
import  com.tianxia.app.floworld.utils.FileUtils;
import  com.tianxia.app.floworld.utils.NetworkUtils;
 
public  class  ConfigCache {
     private  static  final  String TAG = ConfigCache. class .getName();
 
     public  static  final  int  CONFIG_CACHE_MOBILE_TIMEOUT  =  3600000 ;   //1 hour
     public  static  final  int  CONFIG_CACHE_WIFI_TIMEOUT    =  300000 ;    //5 minute
 
     public  static  String getUrlCache(String url) {
         if  (url ==  null ) {
             return  null ;
         }
 
         String result =  null ;
         File file =  new  File(AppApplication.mSdcardDataDir +  "/"  + getCacheDecodeString(url));
         if  (file.exists() && file.isFile()) {
             long  expiredTime = System.currentTimeMillis() - file.lastModified();
             Log.d(TAG, file.getAbsolutePath() +  " expiredTime:"  + expiredTime/ 60000  "min" );
             //1. in case the system time is incorrect (the time is turn back long ago)
             //2. when the network is invalid, you can only read the cache
             if  (AppApplication.mNetWorkState != NetworkUtils.NETWORN_NONE && expiredTime <  0 ) {
                 return  null ;
             }
             if (AppApplication.mNetWorkState == NetworkUtils.NETWORN_WIFI
                    && expiredTime > CONFIG_CACHE_WIFI_TIMEOUT) {
                 return  null ;
             else  if  (AppApplication.mNetWorkState == NetworkUtils.NETWORN_MOBILE
                    && expiredTime > CONFIG_CACHE_MOBILE_TIMEOUT) {
                 return  null ;
             }
             try  {
                 result = FileUtils.readTextFile(file);
             catch  (IOException e) {
                 e.printStackTrace();
             }
         }
         return  result;
     }
 
     public  static  void  setUrlCache(String data, String url) {
         File file =  new  File(AppApplication.mSdcardDataDir +  "/"  + getCacheDecodeString(url));
         try  {
             //建立緩存數據到磁盤,就是建立文件
             FileUtils.writeTextFile(file, data);
         catch  (IOException e) {
             Log.d(TAG,  "write "  + file.getAbsolutePath() +  " data failed!" );
             e.printStackTrace();
         }
     }
 
     public  static  String getCacheDecodeString(String url) {
         //1. 處理特殊字符
         //2. 去除後綴名帶來的文件瀏覽器的視圖凌亂(特別是圖片更須要如此相似處理,不然有的手機打開圖庫,全是咱們的緩存圖片)
         if  (url !=  null ) {
             return  url.replaceAll( "[.:/,%?&=]" "+" ).replaceAll( "[+]+" "+" );
         }
         return  null ;
     }
}

      從實現上咱們全面考慮了幾個細節,註釋已經說明,再也不贅述。
      而後咱們調用方法以下:服務器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void  getConfig(){
         //首先嚐試讀取緩存
         String cacheConfigString = ConfigCache.getUrlCache(CONFIG_URL);
         //根據結果斷定是讀取緩存,仍是從新讀取
         if  (cacheConfigString !=  null ) {
             showConfig(cacheConfigString);
         else  {
             //若是緩存結果是空,說明須要從新加載
             //緩存爲空的緣由多是1.無緩存;2. 緩存過時;3.讀取緩存出錯
             AsyncHttpClient client =  new  AsyncHttpClient();
             client.get(CONFIG_URL,  new  AsyncHttpResponseHandler(){
 
                 @Override
                 public  void  onSuccess(String result){
                     //成功下載,則保存到本地做爲後面緩存文件
                     ConfigCache.setUrlCache(result,  CONFIG_URL);
                     //後面能夠是UI更新,僅供參考
                     showConfig(result);
                 }
 
                 @Override
                 public  void  onFailure(Throwable arg0) {
                     //根據失敗緣由,考慮是顯示加載失敗,仍是再讀取緩存
                 }
 
             });
         }
     }

  這樣配置文件既能有效緩存,又能及時更新了,同時支持離線瀏覽。網絡

7、小結
     智能手機的緩存管理應用很是的廣泛和須要,是提升用戶體驗的有效手段之一。
     固然,緩存管理一些內容沒有細說,如圖片緩存,緩存清理等,這些處理起來比較簡單app

相關文章
相關標籤/搜索