亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

產品設計之路:Android應用-開發技術【數據緩存

系統 2142 0

最近真夠忙的,瞎忙!好久沒寫博客。不知道寫什么,就寫些最近對用戶體驗這塊的一個小的見解吧。

無論大型或小型應用, 靈活的緩存 可以說不僅大大減輕了服務器的壓力,而且因為更快速的用戶體驗而方便了用戶。從事Android開發工作以來,個人認為Android應用可以說是作為小型應用,只是其中很多的開發時間花費在細節之上(UI交互方式、響應速度、效果、字體、顏色等等),其中90%乃至99的應用并不是需要實時更新的(即時通訊類的除外:QQ),而且詬病于蝸牛般的移動網速,3G也是狗屎(至少中國目前是這樣的),與服務器的數據交互是能少則少,這樣用戶體驗才更好。

產品設計之路:Android應用-開發技術【數據緩存】

這是我公司產品(感興趣的朋友可以到這里下載,提有用建議有回報的哦http://www.hulutan.net/ 目前仍在不斷完善,后邊還有驚喜)的截圖,其實這個列表基本上可以全部用緩存數據來處理,即便你有新游戲發布,我不信你一個上百個應用出世。

采用緩存,可以進一步大大緩解數據交互的壓力,又能提供一定的離線瀏覽。下邊我簡略列舉一下緩存管理的適用環境:

1. 提供網絡服務的應用

2. 數據更新不需要實時更新,哪怕是3-5分鐘的延遲也是可以采用緩存機制。

3. 緩存的過期時間是可以接受的(類似網易的新聞閱讀,支持離線離線閱讀)

這樣所帶來的好處:

1. 減小服務器的壓力

2. 提高客戶端的響應速度(本地數據提取嘛)

3. 一定程度上支持離線瀏覽(可以參考網易的那個新聞應用,個人感覺離線閱讀做得非常棒。)

一、 緩存管理的方法

緩存管理的原理很簡:通過時間的設置來判斷是否讀取緩存還是重新下載;斷網下就沒什么好說的,直接去緩存即可。如圖:

產品設計之路:Android應用-開發技術【數據緩存】

里面會有一些細節的處理,后面會詳細闡述。基于這個原理,目前個人用過的兩種比較常見的緩存管理方法是:數據庫和文件(txt)。

二、 數據庫(SQLite)緩存方式

這種方法是在下載完數據文件后,把文件的相關信息如url,路經,下載時間,過期時間等存放到數據庫,當然我個人建議把url作為唯一的標識。下次下載的時候根據url先從數據庫中查詢,如果查詢到當前時間并未過期,就根據路徑讀取本地文件,從而實現緩存的效果。

從實現上我們可以看到這種方法可以靈活存放文件的屬性,進而提供了很大的擴展性,可以為其它的功能提供一定的支持。

從操作上需要創建數據庫,每次查詢數據庫,如果過期還需要更新數據庫,清理緩存的時候還需要刪除數據庫數據,稍顯麻煩,而數據庫操作不當又容易出現一系列的性能,ANR問題,指針錯誤問題,實現的時候要謹慎,具體作的話,但也只是增加一個工具類或方法的事情。

還有一個問題,緩存的數據庫是存放在/data/data/<package>/databases/目錄下,是占用內存空間的,如果緩存累計,容易浪費內存,需要及時清理緩存。

當然這種方法從目前一些應用的實用上看,我沒有發現什么問題,估計使用的量還比較少吧。

本文本人不太喜歡數據庫,原因操作麻煩,尤其是要自己寫建表那些語句,你懂的。我側重文件緩存方式。

三、文件緩存方式

這種方法,使用File.lastModified()方法得到文件的最后修改時間,與當前時間判斷是否過期,從而實現緩存效果。

實現上只能使用這一個屬性,沒有為其它的功能提供技術支持的可能。操作上倒是簡單,比較時間即可,而且取的數據也就是文件里的JSON數據而已。本身處理也不容易帶來其它問題,代價低廉。

四、文件法緩存方式的兩點說明

1. 不同類型的文件的緩存時間不一樣。

籠統的說,不變文件的緩存時間是永久,變化文件的緩存時間是最大忍受不變時間。說白點,圖片文件內容是不變的,一般存在SD卡上直到被清理,我們是可以永遠讀取緩存的。配置文件內容是可能更新的,需要設置一個可接受的緩存時間。

2. 不同環境下的緩存時間標準不一樣。

無網絡環境下,我們只能讀取緩存文件,為了應用有東西顯示,沒有什么過期之說了。

WiFi網絡環境下,緩存時間可以設置短一點,一是網速較快,而是流量不要錢。

3G流量環境下,緩存時間可以設置長一點,節省流量,就是節省金錢,而且用戶體驗也更好。

GPS就別說更新什么的,已經夠慢的了。緩存時間能多長就多長把。

當然,作為一款好的應用,不會死定一種情況,針對于不同網絡變換不同形式的緩存功能是必須有的。而且這個時間根據自己的實際情況來設置:數據的更新頻率,數據的重要性等。

五、何時刷新

開發者一方面希望盡量讀取緩存,用戶一方面希望實時刷新,但是響應速度越快越好,流量消耗越少越好(關于這塊,的確開發中我沒怎么想到,畢竟接口就是這么多,現在公司的產品幾乎點一下就訪問一下,而且還有些雞肋多余的功能。慢慢修改哈哈),是一個矛盾。

其實何時刷新我也不知道,這里我提供兩點建議:

1. 數據的最長多長時間不變,對應用無大的影響。

比如,你的數據更新時間為4小時,則緩存時間設置為1~2小時比較合適。也就是更新時間/緩存時間=2,但用戶個人修改、網站編輯人員等一些人為的更新就另說。一天用戶總會看到更新,即便有延遲也好,視你產品的用途了;如果你覺得你是資訊類應用,再減少,2~4小時,如果你覺得數據比較重要或者比較受歡迎,用戶會經常把玩,再減少,1~2小時,依次類推。

產品設計之路:Android應用-開發技術【數據緩存】

當然類似這個界面的數據我認為更新時間能多長就多長了,盡可能長。如果你拿后邊那個有多少數據會變動來搪塞。我會告訴你:這個只是一個引導性的界面,你有多少款游戲跟用戶半毛錢關系都沒有,10億也跟他沒關,他只要確定這里能找到他要找的 湯姆貓 就行。否則你又失去了一個用戶。

2. 提供刷新按鈕。

必要時候或最保險的方法使在相關界面提供一個刷新按鈕,或者當下流行的下拉列表刷新方式。為緩存,為加載失敗提供一次重新來過的機會。畢竟喝骨頭湯的時候,我也不介意碗旁多雙筷子。

總而言之,一切用戶至上,為了更好的用戶體驗,方法也會層出不窮。 期待更好的辦法

關鍵代碼:

    package com.hulutan.gamestore.cache;

import java.io.File;
import java.io.IOException;

import android.os.Environment;
import android.util.Log;

import com.hulutan.gamestore.Constants;
import com.hulutan.gamestore.GameStoreApplication;
import com.hulutan.gamestore.util.EncryptUtils;
import com.hulutan.gamestore.util.FileUtils;
import com.hulutan.gamestore.util.NetworkUtils;
import com.hulutan.gamestore.util.NetworkUtils.NetworkState;
import com.hulutan.gamestore.util.StringUtils;

/**
 * 緩存工具類
 * @author naibo-liao
 * @時間: 2013-1-4下午02:30:52
 */
public class ConfigCacheUtil {

    private static final String TAG=ConfigCacheUtil.class.getName();

    /** 1秒超時時間 */
    public static final int CONFIG_CACHE_SHORT_TIMEOUT=1000 * 60 * 5; // 5 分鐘

    /** 5分鐘超時時間 */
    public static final int CONFIG_CACHE_MEDIUM_TIMEOUT=1000 * 3600 * 2; // 2小時

    /** 中長緩存時間 */
    public static final int CONFIG_CACHE_ML_TIMEOUT=1000 * 60 * 60 * 24 * 1; // 1天

    /** 最大緩存時間 */
    public static final int CONFIG_CACHE_MAX_TIMEOUT=1000 * 60 * 60 * 24 * 7; // 7天

    /**
     * CONFIG_CACHE_MODEL_LONG : 長時間(7天)緩存模式 <br>
     * CONFIG_CACHE_MODEL_ML : 中長時間(12小時)緩存模式<br>
     * CONFIG_CACHE_MODEL_MEDIUM: 中等時間(2小時)緩存模式 <br>
     * CONFIG_CACHE_MODEL_SHORT : 短時間(5分鐘)緩存模式
     */
    public enum ConfigCacheModel {
        CONFIG_CACHE_MODEL_SHORT, CONFIG_CACHE_MODEL_MEDIUM, CONFIG_CACHE_MODEL_ML, CONFIG_CACHE_MODEL_LONG;
    }

    /**
     * 獲取緩存
     * @param url 訪問網絡的URL
     * @return 緩存數據
     */
    public static String getUrlCache(String url, ConfigCacheModel model) {
        if(url == null) {
            return null;
        }

        String result=null;
        String path=Constants.ENVIROMENT_DIR_CACHE + StringUtils.replaceUrlWithPlus(EncryptUtils.encryptToMD5(url));
        File file=new File(path);
        if(file.exists() && file.isFile()) {
            long expiredTime=System.currentTimeMillis() - file.lastModified();
            Log.d(TAG, file.getAbsolutePath() + " expiredTime:" + expiredTime / 60000 + "min");
            // 1。如果系統時間是不正確的
            // 2。當網絡是無效的,你只能讀緩存
            if(NetworkUtils.getNetworkState(GameStoreApplication.getInstance().getContext()) != NetworkState.NETWORN_NONE) {
                if(expiredTime < 0) {
                    return null;
                }
                if(model == ConfigCacheModel.CONFIG_CACHE_MODEL_SHORT) {
                    if(expiredTime > CONFIG_CACHE_SHORT_TIMEOUT) {
                        return null;
                    }
                } else if(model == ConfigCacheModel.CONFIG_CACHE_MODEL_MEDIUM) {
                    if(expiredTime > CONFIG_CACHE_MEDIUM_TIMEOUT) {
                        return null;
                    }
                } else if(model == ConfigCacheModel.CONFIG_CACHE_MODEL_ML) {
                    if(expiredTime > CONFIG_CACHE_ML_TIMEOUT) {
                        return null;
                    }
                } else if(model == ConfigCacheModel.CONFIG_CACHE_MODEL_LONG) {
                    if(expiredTime > CONFIG_CACHE_MEDIUM_TIMEOUT) {
                        return null;
                    }
                } else {
                    if(expiredTime > CONFIG_CACHE_MAX_TIMEOUT) {
                        return null;
                    }
                }
            }

            try {
                result=FileUtils.readTextFile(file);
            } catch(IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 設置緩存
     * @param data
     * @param url
     */
    public static void setUrlCache(String data, String url) {
        if(Constants.ENVIROMENT_DIR_CACHE == null) {
            return;
        }
        File dir=new File(Constants.ENVIROMENT_DIR_CACHE);
        if(!dir.exists() && Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
            dir.mkdirs();
        }
        File file=new File(Constants.ENVIROMENT_DIR_CACHE + StringUtils.replaceUrlWithPlus(EncryptUtils.encryptToMD5(url)));
        try {
            // 創建緩存數據到磁盤,就是創建文件
            FileUtils.writeTextFile(file, data);
        } catch(IOException e) {
            Log.d(TAG, "write " + file.getAbsolutePath() + " data failed!");
            e.printStackTrace();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 刪除歷史緩存文件
     * @param cacheFile
     */
    public static void clearCache(File cacheFile) {
        if(cacheFile == null) {
            if(Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
                try {
                    File cacheDir=new File(Environment.getExternalStorageDirectory().getPath() + "/hulutan/cache/");
                    if(cacheDir.exists()) {
                        clearCache(cacheDir);
                    }
                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
        } else if(cacheFile.isFile()) {
            cacheFile.delete();
        } else if(cacheFile.isDirectory()) {
            File[] childFiles=cacheFile.listFiles();
            for(int i=0; i < childFiles.length; i++) {
                clearCache(childFiles[i]);
            }
        }
    }
}

  


獲取緩存:

    String cacheConfigString=ConfigCacheUtil.getUrlCache(Net.API_HELP, ConfigCacheModel.CONFIG_CACHE_MODEL_LONG);
        if(cacheConfigString != null) {
               //do something
        }
  


設置緩存:

    ConfigCacheUtil.setUrlCache(data, Net.API_HELP);
  


產品設計之路:Android應用-開發技術【數據緩存】


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲国产一区在线精选 | 久久香蕉国产线看精品 | 国产一区欧美二区 | 久久国产高清一区二区三区 | 国产日产欧产美一二三区 | 亚洲第一永久色 | 亚洲网在线观看 | 久久综合给合久久97色美利坚 | 91福利片| 美女啪啪免费网站 | 99精品免费久久久久久久久日本 | 亚洲成在人线免费视频 | 午夜精品在线免费观看 | 伊人365| 久久99精品久久久久子伦小说 | 黄色a∨ | 欧美成人三级一区二区在线观看 | 成人性色生活片免费网 | 伊人免费网| 久久精品视频6 | 91精品推荐 | 寡妇野外啪啪一区二区 | 夜色私人影院永久地址入口 | 精品国产一区二区三区四 | 最新国产三级久久 | 精品成人一区二区三区免费视频 | 最近中文字幕精彩视频 | 亚洲精品一区二区四季 | 亚洲成a v人片在线观看 | 一级毛片免费观看不收费 | 久久影视一区 | 欧美一级久久久久久久大 | 久久综合影院 | 国产精品久久久久久一区二区 | 亚洲高清免费在线观看 | 国产精品久久久影院 | 羞羞视频在线观看 | 色中色综合 | 日日摸夜夜欧美一区二区 | 一区二区三区中文 | 四虎影视在线观看永久地址 |