Android本地?cái)?shù)據(jù)存儲方案(一)

Android系列的博客主要是記錄和總結(jié)自己在平時(shí)學(xué)習(xí)之中遇到的問題,方便日后用到時(shí)查看,同時(shí)也希望對讀者有所幫助。不足之處,歡迎指正~


在說到Android數(shù)據(jù)存儲之前,先提一下數(shù)據(jù)持久化,所謂數(shù)據(jù)持久化就是將內(nèi)存中的瞬時(shí)數(shù)據(jù)保存下來,在應(yīng)用開發(fā)中是很重要的部分。舉個(gè)栗子,我們打開一個(gè)應(yīng)用之后輸入了用戶名和密碼,之后回到了桌面,再回到應(yīng)用時(shí),我們希望之前輸入的內(nèi)容還在,這個(gè)要怎么實(shí)現(xiàn)呢?可以在回到桌面時(shí)將數(shù)據(jù)保存,返回視圖時(shí)再填入數(shù)據(jù)。

其實(shí)不止是這些瞬時(shí)數(shù)據(jù)的保存,包括一些和應(yīng)用相關(guān)的數(shù)據(jù)也是需要保存的,比如用戶第一次登陸之后,之后再進(jìn)入應(yīng)用不必再次登陸,那么用戶的信息就需要保存下來。下面進(jìn)入正題。

注意:數(shù)據(jù)持久化應(yīng)該結(jié)合Activity的生命周期使用。

Android本地?cái)?shù)據(jù)存儲有以下幾種方式:

  1. SharedPreferences:用戶偏好設(shè)置
  2. 內(nèi)部存儲,數(shù)據(jù)存儲到手機(jī)內(nèi)置存儲器
  3. 外部存儲,外部SD卡中存儲數(shù)據(jù)
  4. SqlLite本地?cái)?shù)據(jù)庫存儲
  5. ContentProvider

其中內(nèi)部存儲和外部存儲都屬于文件存儲,這次主要是介紹SharedPreferences和內(nèi)部存儲。

1. SharedPreferences:用戶偏好設(shè)置

SharedPreferences使用鍵值對來存儲數(shù)據(jù),默認(rèn)以xml文件形式進(jìn)行存儲,對應(yīng)的文件保存到手機(jī)內(nèi)存的data/<application package>/xxx(保存數(shù)據(jù)時(shí)建立的文件)目錄下面,提供和putString(),putInt(),putBoolean()等方法存儲不同類型的數(shù)據(jù),使用時(shí)很方便。

因?yàn)镾haredPreferences存儲時(shí)的數(shù)據(jù)格式和數(shù)據(jù)類型限制,它只適用于存儲一些簡單用戶設(shè)置,例如用戶設(shè)置的夜間模式,音量,或者登錄信息等。

如何獲取SharedPreferences

Android提供了3中方法獲取SharedPreferences對象。

1) Context 類中的 getSharedPreferences()方法

參數(shù):getSharedPreferences()需要如下兩個(gè)參數(shù)
String類型:指定文件名(不需要帶文件后綴)
int類型:指定文件的操作模式,常用的是MODE_PRIVATE (該文件只允許本應(yīng)用程序進(jìn)行讀寫),MODE_APPEND(對文件進(jìn)行寫入操作時(shí),是在文件尾追加內(nèi)容),MODE_MULTI_PROCESS (用于會有多個(gè)進(jìn)程中對同一個(gè) SharedPreferences 文件進(jìn)行讀寫的情況)。

2) Activity 類中的 getPreferences()方法

參數(shù):只接收一個(gè)操作模式參數(shù)。
這個(gè)方法時(shí)會自動將當(dāng)前活動的類名作為 SharedPreferences 的文件名。

3) PreferenceManager 類中的 getDefaultSharedPreferences()方法

這是一個(gè)靜態(tài)方法,它接收一個(gè) Context 參數(shù),并自動使用當(dāng)前應(yīng)用程序的包名作為前綴來命名 SharedPreferences 文件

以下是代碼案例(以保存登錄信息為例):
獲取SharedPreferences對象

preferences = getSharedPreferences("login",MODE_PRIVATE);

存儲用戶登錄的信息

//獲取editor對象
    SharedPreferences.Editor editor = preferences.edit();
   //存儲數(shù)據(jù)時(shí)選用對應(yīng)類型的方法
    editor.putString("userId",user.getUserId());
    editor.putString("username",user.getUserName());
    editor.putString("password",user.getPassword());
    editor.putString("role",user.getUserRole());
    //提交保存數(shù)據(jù)
    editor.commit();

取出數(shù)據(jù)
取出數(shù)據(jù)之前要先獲得SharedPreferences對象。

//取出數(shù)據(jù),第一個(gè)參數(shù)是存取的鍵,第二個(gè)參數(shù)-->如果該key不存在,返回默認(rèn)值,這里返回的默認(rèn)值是""
    String userId = preferences.getString("username","");
    String password = preferences.getString("password","");
    String role = preferences.getString("role","");

2. 文件存儲

文件存儲的形式不對文件進(jìn)行任何格式化處理,存入是什么樣,取出來也是什么樣,我們可以用它存儲一些簡單類型的數(shù)據(jù)或二進(jìn)制數(shù)據(jù),也可以自己定義存儲規(guī)范,用來存儲復(fù)雜的文本數(shù)據(jù)。其實(shí)我們可以直接存儲json格式的數(shù)據(jù)在文件中,借助Gson類進(jìn)行對象和json格式之間的轉(zhuǎn)換,使用很方便。上次我就在應(yīng)用中用文件緩存了數(shù)據(jù),比起SQLLite,有時(shí)文件存儲要方便一些,因?yàn)樗挥眠M(jìn)行創(chuàng)建數(shù)據(jù)庫,建表等操作。

內(nèi)部存儲:Context提供了很方便的打開文件的方法??梢允褂肅ontext類提供的openFileOutput (),和openFileInput ()進(jìn)行文件寫入和讀取,進(jìn)行緩存的設(shè)置和讀取,需要注意的是,這里傳入的文件名是帶有文件后綴的。
注意:在讀寫是文件時(shí)可以加入讀寫緩沖,加快讀寫效率。

以下是文件存儲的內(nèi)部存儲的例子(以存儲字符串為例):
為了以后使用方便,可以先定義一個(gè)文件緩存的工具類。

public class FileCacheUtil {
    //定義緩存文件的名字,方便外部調(diào)用
    public static final String docCache = "docs_cache.txt";//緩存文件
    //緩存超時(shí)時(shí)間
    public static final int CACHE_SHORT_TIMEOUT=1000 * 60 * 5; // 5 分鐘

    /**設(shè)置緩存
    content是要存儲的內(nèi)容,可以是任意格式的,不一定是字符串。
    */
    public static void setCache(String content,Context context, String cacheFileName,int mode) {
        FileOutputStream fos = null;
        try {
            //打開文件輸出流,接收參數(shù)是文件名和模式
            fos = context.openFileOutput(cacheFileName,mode);
            fos.write(content.getBytes());
         } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //讀取緩存,返回字符串(JSON)
    public static String getCache(Context context, String cacheFileName) {
        FileInputStream fis = null;
        StringBuffer sBuf = new StringBuffer();
        try {
            fis = context.openFileInput(cacheFileName);
            int len = 0;
            byte[] buf = new byte[1024];
            while ((len = fis.read(buf)) != -1) {
                sBuf.append(new String(buf,0,len));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        if(sBuf != null) {
             return sBuf.toString();
        }
        return null;
    }

    public static String getCachePath(Context context) {
        return context.getFilesDir().getAbsolutePath();
    }
}

使用
使用文件緩存工具類時(shí),直接調(diào)用它對外提供的函數(shù)就可以,將需要數(shù)據(jù)以字符串形式存,我們可以自定義數(shù)據(jù)存儲格式,比如說以JSON串存儲。以上代碼中,緩存文件名寫到文件緩存的類中,使用的時(shí)候可以直接調(diào)用。

提示:可以在Activity的onResume()的方法中使用獲取緩存的操作(結(jié)合Activity來看),在onPause()是使用設(shè)置緩存的操作(暫停,跳轉(zhuǎn)到其他Activity時(shí)調(diào)用這個(gè)方法)。

在應(yīng)用中我們可以根據(jù)是否有網(wǎng)絡(luò)或著緩存是否過期來判斷是否從文件中獲取緩存數(shù)據(jù)。以下是判斷緩存是否過期的方法。

//判斷緩存是否過期,比較文件最后修改時(shí)間
private boolean cacheIsOutDate(String cacheFileName) {    
    File file = new File(FileCacheUtil.getCachePath(mContext) + "/" 
                 + cacheFileName);    
    //獲取緩存文件最后修改的時(shí)間,判斷是是否從緩存讀取    
    long date = file.lastModified();    
    long time_out = (System.currentTimeMillis() - date);    
    if (time_out > FileCacheUtil.CACHE_SHORT_TIMEOUT) {           
        return true;    
    }       
    return false;//未過期
}

總結(jié)

最后總結(jié)一下Context中獲取內(nèi)部存儲和外部存儲文件路徑的方法。這些目錄下的文件都會隨著應(yīng)用的卸載而被刪除。
context.getFilesDir():獲取手機(jī)內(nèi)置存儲器的/data/data/<application package>/files目錄,這個(gè)位置放存儲文件。
context.getCacheDir():獲取手機(jī)內(nèi)置存儲器的/data/data/<application package>/cache目錄,這個(gè)目錄可以存放應(yīng)用緩存文件。
context.getExternalFilesDir():獲取SDCard/Android/data/你的應(yīng)用的包名/files/ 目錄,是外部存儲的目錄,當(dāng)我們使用外部存儲時(shí),應(yīng)該先判斷外部存儲介質(zhì)是否存在,同時(shí)還要在應(yīng)用權(quán)限中加入對sd卡的讀寫操作。

//判斷外部SD卡是否存在,true是存在
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 任何一個(gè)應(yīng)用程序,其實(shí)說白了就是在不停地和數(shù)據(jù)打交道,我們聊QQ、看新聞、刷微博,所關(guān)心的都是里面的數(shù)據(jù),...
    AndYMJ閱讀 1,931評論 2 5
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,113評論 25 709
  • 最近在折騰完房子之后,開始考慮自己的職業(yè)發(fā)展,準(zhǔn)備試試新機(jī)會,謀求一個(gè)突破。 然后就是一個(gè)又一個(gè)打擊,要么被待定,...
    bluescorpio閱讀 1,176評論 0 1
  • 你學(xué)習(xí)一般,考上了現(xiàn)在的這所學(xué)校,成績不算好,拿不到獎(jiǎng)學(xué)金,上課不聽講,上自習(xí)不規(guī)律,考試靠突擊,同學(xué)幫一把的話也...
    胡星星閱讀 213評論 0 0
  • 清泉石上流,無聲石字留; 篆書鐫刻成,有緣石自秀; 山河孕千年,相會不舍丟; 勤放書案前,信心誠石修。 ...
    一真書苑閱讀 568評論 3 2

友情鏈接更多精彩內(nèi)容