【Android API Guides 簡譯(三)】Data Storage--Storage Options

Android提供了幾種永久儲存手機數據的選項,而我們選擇存儲的方式依據於我們存儲的不同的特定需求,比如你的數據是否需要只對自己公開,數據是否可以被其他應用得到或者你想要儲存多大的數據。
數據存儲的方式如下:
Shared Preferences
通過xml類型的鍵值對,存儲私密的原始數據。
Internal Storage 內部存儲
通過手機內存存儲私密數據
External Storage 外部存儲
在設備外部共享裏存儲公開的數據
SQLite Databases Android 原生內部數據庫
在私有數據庫裏存儲結構化的數據
Network Connection 網絡連接
在網絡服務器上存儲數據
Android 還提供了一種將私有的數據公開化的組件–Content-providers,詳見Content-providers參考文檔。

一、使用Shared Preferences
SharedPreferences類提供了一個完整的框架用來通過鍵值對的形式,永久地儲存私有信息。我們可以使用SharedPreferences類儲存任意一種類型的數據,包括booleans, floats, ints, longs, and strings。而且這些數據將會在整個會話階段一直保存,即使你的應用被關閉。
得到SharedPreferences對象的兩種方式:
1、getSharedPreferences() - 如果你想要得到一個通過鍵名來區分的籠統的Preferences對象,使用這種方法。
2、getPreferences(int) - 如果你的整個Activity只需要一個Preferences,因此你不需要提供鍵名。使用這種方法。
寫入Value值的方式:
1、使用edit()方法得到一個 SharedPreferences.Editor對象。
2、通過類似putBoolean() 和 putString() 的方法添加值。
3、將編輯器的值和SharedPreferences對象的值相關聯。
讀取Value值,通過SharedPreferences類的方法,比如getBoolean() 和 getString() 。
示例代碼:

public class Calc extends Activity {
    public static final String PREFS_NAME = "MyPrefsFile";

    @Override
    protected void onCreate(Bundle state){
       super.onCreate(state);
       . . .

       // Restore preferences
       SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
       boolean silent = settings.getBoolean("silentMode", false);
       setSilent(silent);
    }

    @Override
    protected void onStop(){
       super.onStop();

      // We need an Editor object to make preference changes.
      // All objects are from android.context.Context
      SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
      SharedPreferences.Editor editor = settings.edit();
      editor.putBoolean("silentMode", mSilentMode);

      // Commit the edits!
      editor.commit();
    }
}

二、使用Internal Storage
你可以直接將數據存儲在內部存儲裏,但一般情況下,內部存儲的數據對於本程序是私有的,其他程序是無法訪問到的,也就是說當本程序被卸載時,該數據會一起被移除。我們一般將內部文件放在Data/data/相應的應用目錄。
創建或者向內部存儲寫入一個文檔的過程如下:
1、調用openFileOutput()方法,參數是文件名字和類型,返回一個FileOutputStream對象。
2、用write()寫入文檔
3、用close()關閉文檔
示例代碼:

String FILENAME = "hello_file";
String string = "hello world!";

FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();

MODE_PRIVATE將會創建或者取代相同名字的文件,而且這個文件只對本程序可用。其他的模式有:MODE_APPEND, MODE_WORLD_READABLE, 和 MODE_WORLD_WRITEABLE。
如果我們有讀取一個內容固定不變的文件,可以在編譯的時候,在R.raw目錄下保存你想要訪問的文件,然後調用 openRawResource(),參數是R.raw.,返回一個 InputStream 對象,通過這個流,讀取你想要讀取的內容。(但是你不可以對這個文件進行寫入操作。)
保存臨時文件
如果你並不想永久的保存某些數據,你可以通過調用getCaheDir()方法,在系統目錄裏創建打開一個文件,用來保存臨時數據。方法返回值是保存臨時文件的路徑。
當系統的內部存儲快滿了時,系統會自動清理臨時文件,但是你不能依靠系統自動來清理臨時文件,需要自己設置臨時文件的大小上限,定時刪除臨時文件。當使用者卸載應用時,臨時數據都會被刪除。
其他有用的方法
getFilesDir()
得到保存文件的絕對路徑。
getDir()
創建或者打開一個存在的內部存儲文件。
deleteFile()
刪除一個保存在內部存儲的文件。
fileList()
返回應用的目錄下的文件的清單。

三、使用外部存儲
任何一個Android兼容性的手機都支持共享你保存在“外部存儲”的文件。所謂”外部存儲“,既可以保存在可移除的SD卡,也包含不可移除的內部存儲裏。而且當我們通過USB連接電腦時,我們可以修改這些文件。
注意:當我們在電腦上加載外部存儲時,手機內不可訪問相應的文件。存儲在外部存儲的文件不受安全性保護,用戶可以任意的增加修改或者刪除該文件。
訪問到外部存儲
你必須擁有 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 權限,才能訪問或寫入外部存儲的文件。
在工程的Manifest.xml裏修改:

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

當我們既想讀取又想寫入時,只需要得到 WRITE_EXTERNAL_STORAGE 權限就可以。
注意:從4.4版本後,如果只是訪問和寫入對本應用私有的文件,不需要獲得上述權限。
檢查媒體的可用性
在我們使用外部存儲的文件之前,都必須檢查文件的可用性,即文件是否只讀,隱藏或者其他狀態。我們會用getExternalStorageState(),返回一個String對象。通過將String值與MEDIA_MOUNTED,MEDIA_MOUNTED_READ_ONLY等來確認當前文件的狀態。下面提供了兩種檢查文件的可用性的方法:

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

保存可被其他應用共享的文件
我們通常把想要共享的文件放在具有共享屬性的文件目錄下,那麼怎麼創建具有共享屬性的文件目錄呢?調用getExternalStoragePublicDirectory()創建一個文件目錄,通過參數目錄類型和目錄名稱,設置文件目錄的屬性和名稱。
實例代碼:

public File getAlbumStorageDir(String albumName) {
    // Get the directory for the user's public pictures directory.
    File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

保存私有文件
你可以通過調用getExternalFilesDir()方法來創建隱藏文件目錄,同時可以通過設置參數的值來標示該目錄的類型,比如DIRECTORY_MOVIES,標明該文件目錄裏的文件是視頻類型的。
上文提到過,4.4以後無需設置權限即可訪問外部存儲的文件。低版本的需要如下設置,類似前面:

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                     android:maxSdkVersion="18" />
    ...
</manifest>

注意:當用戶將應用卸載後,該文件會一起被移除。因爲該文件不會被文件系統掃描到,所以通過content provider組件是無法訪問到這些文件的。因此,如果當用戶在此程序生成的文件不能保存在私有目錄下,否則用戶無法通過其他應用找到這些文件。
有時候,設備會將內部存儲劃分一部分當做外部存儲使用,於是在4.3及以下版本時,調用 getExternalFilesDir() 方法不能訪問到被劃作外部存儲的內部存儲的文件,但在4.4版本以後,調用getExternalFilesDir() 方法,我們可以訪問到兩部分的文件。這時候getExternalFilesDir() 方法返回一個文件名條目,第一個條目就是被劃作外部存儲的目錄。而且此目錄是基本目錄,除非在該目錄已滿或者無法訪問的情況下,否則優先使用這部分存儲。
當然如果你不喜歡這種設計的API,你可以使用support library裏的靜態方法ContextCompat.getExternalFilesDirs()。
注意:儘管私有目錄下的文件不可被content provider組件使用,但是如果想要完全保密的話,還是要存儲在內部存儲裏,因爲私有目錄裏文件可以被具有 READ_EXTERNAL_STORAGE權限的應用訪問到。
保存臨時文件
同內部存儲裏保存臨時文件一樣,可以調用getExternalCacheDir()創建臨時文件。也同樣的,被卸載時會被移除。

四、使用數據庫
Android自帶 SQLite 數據庫,但只能在創建該數據庫的應用中使用,其他應用不能使用。
創建數據庫的推薦方法是創建繼承SQLiteOpenHelper的類,並重寫OnCreate()方法。
示例如下:

public class DictionaryOpenHelper extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 2;
    private static final String DICTIONARY_TABLE_NAME = "dictionary";
    private static final String DICTIONARY_TABLE_CREATE =
                "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" +
                KEY_WORD + " TEXT, " +
                KEY_DEFINITION + " TEXT);";

    DictionaryOpenHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(DICTIONARY_TABLE_CREATE);
    }
}

你可以得到一個按照你規定的方法的SQLiteOpenHelper對象,然後分別調用getWritableDatabase() and getReadableDatabase()方法來得到 SQLiteDatabase對象,通過對這個對象進行操作來完成數據庫的功能。
SQLiteDatabase對象可以通過調用query()進行大部分的查詢,更復雜的查詢比如得到列名,可以通過 SQLiteQueryBuilder對象進行查詢。
每個SQLite查詢都會得到Cursor。Cursor即索引,只想每一個想要查詢的數據。
數據庫調試
Android SDK包含一個叫作 sqlite3的數據庫,我們可以進行試操作。

五、使用網絡連接
我們還可以通過網上的服務器儲存和恢復數據,這裏不再詳述。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章