App緩存管理
無論大型或小型應用,靈活的緩存可以說不僅大大減輕了服務器的壓力,而且因爲更快速的用戶體驗而方便了用戶。
Android的apk可以說是作爲小型應用,其中99%的應用並不是需要實時更新的,而且詬病於蝸牛般的移動網速,與服務器的數據交互是能少則少,這樣用戶體驗才更好,這也是我們有時捨棄webview而採用json傳輸數據的原因之一。
採用緩存,可以進一步大大緩解數據交互的壓力,特此,我們簡略列舉一下緩存管理的適用環境:
1. 提供網絡服務的應用
2. 數據更新不需要實時更新,但是哪怕是3-5分鐘的延遲也是可以採用緩存機制。
3. 緩存的過期時間是可以接受的(不會因爲緩存帶來的好處,導致某些數據因爲更新不及時而影響產品的形象等)
帶來的好處:
1. 服務器的壓力大大減小
2. 客戶端的響應速度大大變快(用戶體驗)
3. 客戶端的數據加載出錯情況大大較少,大大提高了應有的穩定性(用戶體驗)
4. 一定程度上可以支持離線瀏覽(或者說爲離線瀏覽提供了技術支持)
一、緩存管理的方法
這裏的緩存管理的原理很簡:通過時間的設置來判斷是否讀取緩存還是重新下載。
裏面會有一些細節的處理,後面會詳細闡述。
基於這個原理,目前鄙人見過的兩種比較常見的緩存管理方法是:數據庫法和文件法。
二、數據庫法緩存管理
這種方法是在下載完數據文件後,把文件的相關信息如url,路經,下載時間,過期時間等存放到數據庫,下次下載的時候根據url先從數據庫中查詢,如果查詢到當前時間並未過期,就根據路徑讀取本地文件,從而實現緩存的效果。
從實現上我們可以看到這種方法可以靈活存放文件的屬性,進而提供了很大的擴展性,可以爲其它的功能提供一定的支持;
從操作上需要創建數據庫,每次查詢數據庫,如果過期還需要更新數據庫,清理緩存的時候還需要刪除數據庫數據,稍顯麻煩,而數據庫操作不當又容易出現一系列的性能,ANR問題,實現的時候要謹慎,具體作的話,但也只是增加一個工具類或方法的事情。
還有一個問題,緩存的數據庫是存放在/data/data/<package>/databases/目錄下,是佔用內存空間的,如果緩存累計,容易浪費內存,需要及時清理緩存。
當然這種方法從目前一些應用的實用上看,我沒有發現什麼問題。
本文我側重強調第二種方法,第一種方法的實現,就此掠過。
三、文件法緩存管理
這種方法,使用File.lastModified()方法得到文件的最後修改時間,與當前時間判斷是否過期,從而實現緩存效果。
實現上只能使用這一個屬性,沒有爲其它的功能提供技術支持的可能。
操作上倒是簡單,比較時間即可。本身處理也不容易帶來其它問題,代價低廉。
四、文件法緩存管理的兩點說明
1. 不同類型的文件的緩存時間不一樣。
籠統的說,不變文件的緩存時間是永久,變化文件的緩存時間是最大忍受不變時間。
說白點,圖片文件內容是不變的,直到清理,我們是可以永遠讀取緩存的。
配置文件內容是可能更新的,需要設置一個可接受的緩存時間。
2. 不同環境下的緩存時間標準不一樣。
無網絡環境下,我們只能讀取緩存文件,哪怕緩存早就過期。
WiFi網絡環境下,緩存時間可以設置短一點,一是網速較快,而是流量不要錢。
移動數據流量環境下,緩存時間可以設置長一點,節省流量,就是節省金錢,而且用戶體驗也更好。
舉個例子吧,最近本人在做的一個應用在wifi環境下的緩存時間設置爲5分鐘,移動數據流量下的緩存時間設置爲1小時。
這個時間根據自己的實際情況來設置:數據的更新頻率,數據的重要性等。
五、何時刷新
開發者一方面希望儘量讀取緩存,用戶一方面希望實時刷新,但是響應速度越快越好,流量消耗越少越好,是一個矛盾。
其實何時刷新我也不知道,這裏我提供兩點建議:
1. 數據的最長多長時間不變,對應用無大的影響。
比如,你的數據更新時間爲1天,則緩存時間設置爲4~8小時比較合適,一天他總會看到更新,如果你覺得你是資訊類應用,再減少,2~4小時,如果你覺得數據比較重要或者比較受歡迎,用戶會經常把玩,再減少,1~2小時,依次類推。
爲了保險起見,你可能需要毫無理由的再次縮減一下。
2. 提供刷新按鈕。
上面說的保險起見不一定保險,最保險的方法使在相關界面提供一個刷新按鈕,爲緩存,爲加載失敗提供一次重新來過的機會,有了這個刷新按鈕,我們的心也才真的放下來。
六、文件緩存法的具體實現
針對配置文件的緩存,我新建了一個類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) { //根據失敗原因,考慮是顯示加載失敗,還是再讀取緩存 } }); } } |
這樣配置文件既能有效緩存,又能及時更新了,同時支持離線瀏覽。
七、小結
智能手機的緩存管理應用非常的普遍和需要,是提高用戶體驗的有效手段之一。
當然,緩存管理一些內容沒有細說,如圖片緩存,緩存清理等,這些處理起來比較簡單。