Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android存儲選擇

Android存儲選擇

編輯:關於Android編程

最近翻譯了一篇Android Developer上的文章,文章的原路徑是Storage Options。這篇文章說的是Android中的存儲選擇。

Android為我們提供了幾種存儲穩固的應用數據的選擇。你選擇的方法取決於你的具體的需求,例如數據是否應該是對於當前應用是私有的或者對於其他的應用是可訪問的,還有你的數據需要多大的空間。
你的數據存儲方式如下:

Shared Preferences:
用key-value的方式存儲基本的私有數據。

Internal Storage:(內部存儲)
在設備內存上存儲私有數據。

External Storage:(外部存儲)
在擴展存儲上存儲共有的數據。

SQLite Databases:
在私有數據庫上存儲有組織的數據。

Network Connection:
使用你自己的網絡服務器再往上存儲數據。

Android提供了一種方式去向其他的Android應用暴露你的數據甚至包括私有數據,也就是content provider。content provider是一個可選擇的控件,它暴露了你的應用數據的讀或者寫的權限,受限於任何你想要加的限制。如果你想了解更多關於 content provider的信息,去看content provider的文檔。

Using Shared Preferences

SharedPreferences類提供了一個框架,它允許你去存儲和取回以key-value格式的數據。你可以使用SharedPreferences去存儲任何基本數據類型:booleans, floats, ints, longs, 和strings。這個數據將會持續用戶周期(即使你的應用已經被殺死了)。
Shared Preferences並不是嚴格地用來存儲用戶偏好的,例如用戶選擇了什麼鈴聲。如果你對於為你的應用創建用戶偏好(user preferences)感興趣,看PreferenceActivity,它提供了一個Activity框架去創建user preferences,它將自動使用Shared Preferences。

你可以使用以下的方法去為你的應用獲取一個SharedPreferences對象:
getSharedPreferences():如果你需要多個由名字區分的preferences的文件,你用第一個參數來區分這些文件,你可以使用這個方法。
getPreferences():如果你只需要為你的Activity提供一個preferences文件,你可以使用這個方法。因為這僅僅是一個針對你的Activity的 preferences 文件,你不必提供一個名字來區分。

來寫值:
1. 調用edit()去獲取SharedPreferences.Editor。
2. 使用這些方法putBoolean()等來添加值。
3. 用commit()來提交這些新的值。

用getBoolean()等方法來讀取存儲的值。

這是一個在一個計算器裡為鍵盤按鍵存儲preference的例子:

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();
    }
}

使用內部存儲

你可以在設備的內部存儲上直接存放文件。默認情況下,存儲到內部存儲的文件對於你的應用是私有的並且其他的應用不能獲取到它們。當用戶卸載了你的應用時,這些文件也同時被移除了。
為了創建和寫入一個私有的文件到內部存儲:
1. 調用openFileOutput()方法,它會返回一個FileOutputStream。
2. 用write()去寫到文件裡。
3. 用close()去關閉我們的流(stream)。

例如:

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。

從內部存儲中讀取一個文件:
1. 調用openFileInput(),它返回了FileInputStream。
2. 用read()從文件中讀取字節。
3. 用close()關閉文件流。

Tip:如果你想在編譯的時候去在你的應用裡存儲一個文件,存儲你的文件在這個項目目錄:res/raw/。你可以用openRawResource()打開它,傳遞參數 R.raw.<文件名> 。這種方式返回InputStream,你可以用這個流去讀這個文件。(但是你不能對最初的文件進行寫操作)

存儲緩存文件

如果你想緩存一些數據,而不是一直存儲它們,你可以使用getCacheDir()去打開一個文件,這個文件指的是你的應用存儲臨時緩存文件的內部目錄。
當設備的內部存儲空間不足時,Android有可能刪除這些緩存文件來釋放空間。但是,你不應該依賴系統去清理這些緩存文件。你應該自己去控制緩存文件的添加和刪除並且保持它們占據的空間在一個合理的范圍內(例如1MB)。當用戶卸載你的應用時,這些文件將被移除。

其它有用的方法

getFilesDir():
獲取你的內部文件被存儲的文件系統的目錄的絕對路徑。
getDir():
創建(或者打開一個已經存在的)一個內部存儲空間的目錄。
deleteFile():
刪除內部存儲裡的一個文件。
fileList():
返回目前被你的應用存儲的文件的一個列表。

使用擴展存儲

每部Android設備都會支持用來存儲文件的外部存儲。外部存儲可以是一個可以移除的媒介(例如SD卡)或者一個內部存儲(不可移除的)。存儲在外存的文件是全局可讀的並且可以被允許USB mass 存儲的用戶所修改。
注意:如果用戶在電腦上增加了外部存儲或者移除了媒介,外部存儲將會變得不可用。並且你存儲到外存的文件也會沒有安全保證。所有的應用都可以讀寫放置在外存的文件並且他們也可以刪除它們。

獲取外部存儲的權限

為了在外部存儲器上讀寫文件,你的應用必須獲取READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE系統權限。例如:


    
    ...

如果你想同時讀寫文件,你只需要添加WRITE_EXTERNAL_STORAGE權限,因為它已經包括了讀權限。

提示:從Android 4.4版本開始,如果你僅僅讀寫你應用的私有文件,這些允許並不是必須的。更多的內容,見saving files that are app-private。

檢查媒介的可用性

在你操作外存之前,你應該調用getExternalStorageState()去檢查當前媒介(外部存儲目錄)是否可用。這個媒介將會被添加到電腦,丟失,只讀,或者在其它的狀態。例如,下面的方法你可以用來檢測存儲介質的可用性:

/* 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;
}

getExternalStorageState()方法會返回其它的狀態,例如這個介質是否在被共享(連接到了電腦),丟失了,被錯誤地移除等等。當你的應用需要外部存儲的權限的時候,你可以使用這些返回值去告訴用戶目前的外部存儲的狀態。

存儲可以與其它應用共享的文件

通常地,用戶可以通過你的APP得到的新的文件應該存儲在一個公用的地方,在這個公用的地方其它的APP可以訪問他們並且用戶可以從設備中輕易的拷貝它們。當這麼做的時候,你應該使用共享的公有目錄之一,例如:Music/, Pictures/, and Ringtones/。
調用getExternalStoragePublicDirectory()方法,通過傳遞某種你需要的目錄的類型,例如DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTORY_RINGTONES(鈴聲目錄)等,去獲取相應公有目錄裡的文件。通過存儲你的文件到相應的目錄中,系統的掃描器將會對你的文件進行分類。(例如,鈴聲將在系統中被設置為鈴聲的目錄,而不是音樂)
例如,這裡是一個在公有的照片目錄為新的相冊創建目錄的方法:

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;
}

把你的文件藏起來放置文件掃描儀把它掃描出來(隱藏自己的文件)
你可以在你的外存目錄下包含一個名叫 .nomedia 的空文件(在文件名裡注意點的前綴)。這將放置Android系統去獲取到你的文件並且通過MediaStore content provider把它們提供給其它的應用。但是,如果你的文件的確對於你的應用是私有的,你應該把它們存儲在app的私有目錄(save them in an app-private directory)。

存儲應用的私有文件

如果你想處理並不想給其它應用使用的文件(例如僅僅由你的應用使用的圖片或者音效),你應該通過調用getExternalFilesDir()在外部存儲中去使用私有的存儲目錄。這個方法同樣需要一個參數去區分子目錄的類型(例如DIRECTORY_MOVIES)。如果你不需要一個特殊的外接媒介目錄,傳遞null去過去你的私有應用目錄的根目錄。
從Android 4.4版本開始,在你的app 私有目錄讀寫文件不再需要READ_EXTERNAL_STORAGE 或WRITE_EXTERNAL_STORAGE權限。所以你只用在更低的Android版本通過添加maxSdkVersion屬性去聲明這個權限,如下:


    
    ...

注意:當用戶卸載了你的應用時,這個目錄以及它的內容都將被刪除。同樣地,系統掃描將不會讀取這些目錄下的文件,所以MediaStore content provider將不會獲取到它們的內容。同樣地,你不應該使用這些目錄來存儲最後屬於用戶的文件,例如照片或者你購買的音樂,這些文件應該存放在公有目錄裡。

有些時候,有一部分內存被分配用作外部存儲的Android設備可能仍會提供一個SD卡插槽。當在Android 4.3或者更低的版本時,getExternalFilesDir()方法僅僅提供了內部分配(內存)的權限並且你的app不能讀寫sd卡。但是,從Android 4.4版本開始,你可以通過調用返回文件數組的方法getExternalFilesDirs()去獲得以上兩個目錄的權限。數組中的第一個入口是主要的外部存儲,並且除非它滿了或者是不可用,你都應該使用這個地址目錄。如果你想在Android 4.3或以下的設備去同時獲取以上這兩個目錄,你可以使用support library 裡的靜態方法ContextCompat.getExternalFilesDirs()。
這個方法同樣包含一個文件數組,但是在Android 4.3或更低的版本上只有一個入口。

注意:盡管由getExternalFilesDir() 和getExternalFilesDirs()提供的目錄不能被MediaStore content provider所訪問,擁有READ_EXTERNAL_STORAGE權限的其他應用可以訪問所有外部存儲包括上面目錄裡的文件。如果你想完全限制你的文件的訪問權限,你應該把你的文件寫到內存存儲中去。

存儲緩存文件

調用getExternalCacheDir()方法去打開你認為在外存上應該去存儲的緩存文件。如果用戶卸載了你的應用,這些文件將會被自動刪除。
與ContextCompat.getExternalFilesDirs()類似,我們在上面提過的,你同樣可以通過調用
ContextCompat.getExternalCacheDirs()方法在二級外存目錄(如果可訪問)上去訪問緩存目錄。

小提示:為了保存你的文件空間和保證你應用的性能,細致地操作你的緩存文件並且在你的應用的生命周期中去刪除無用的緩存是非常重要的。

使用數據庫

Android 為SQLite數據庫提供了完整的支持。任何你創建的數據庫可以在你的應用裡通過名字去獲取,但是在應用外則不可以訪問。
Android推薦的創建新的數據庫的方法是創建一個SQLiteOpenHelper的子類並且重載onCreate()方法,在這個方法中你可以通過SQLite指令去創建數據庫中的表。
例如:

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() 和 getReadableDatabase() 去讀寫數據庫。它們都返回了SQLiteDatabase對象,並且為我們的數據庫操作提供了相應的方法。

你可以通過使用參數包括表名,選擇條件,列,排序等的SQLiteDatabase query()方法去使用SQLite查詢語句。對於像這些需要列別名的復雜的查詢,你應該使用提供了很多便捷方法去創建查詢語句的SQLiteQueryBuilder。

每個SQLite查詢都會返回一個指向通過這次查詢找到的所有行的Cursor。Cursor通常是一個幫助你來導航數據庫查詢結果的機制。

例如,你可以看Note Pad和Searchable Dictionary應用去看如何在Android中使用SQLite數據庫。

數據庫調試

Android SDK包含了一個sqlite3工具,它幫助我們去浏覽表的內容,運行數據庫指令,並且使用其它有用的數據庫功能。看Examining sqlite3 databases from a remote shell如何去使用這個功能。

注意:Android沒有為SQLite施加任何限制。我們推薦在你的表裡應該包含一個自增長的值域,我們可以通過它去迅速定位一條記錄。這對於私有數據並不是必須的,但是當你聲明了一個content provider,你必須使用BaseColumns._ID常量去包含一個獨一無二的ID。

使用網絡連接

你可以使用網絡(當它可用時)去存儲和取數據。為了做網絡操作,使用下面包裡的類:

java.net.*
android.net.*
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved