Storage Options 可选的存储方式
STORAGE 快速预览
- Use Shared Preferences for primitive data
- Use internal device storage for private data
- Use external storage for large data sets that are not private
- Use SQLite databases for structured storage
在本文档中
- Using Shared Preferences
- Using the Internal Storage
- Using the External Storage
- Using Databases
- Using a Network Connection
另请参阅
安卓提供了几种保存永久用户数据的方式。选择那种方式取决于你的实际需要:你想要似有还是和其他应用程序分享,以及你的数据需要的空间。
几种数据存储方式:
-
Shared Preferences
- 以键值对的方式存储似有原始数据。 Internal Storage
- 存储似有数据到设备存储器中。 External Storage
- 存储公有数据到可分享的外部存储器中。 SQLite Databases
- 存储结构化数据到私有数据库中。 Network Connection
- 使用你自有的网络服务存储数据到网络上。
安卓允许你使用 【内容提供者】来暴露数据,也包括私有数据。
Using Shared Preferences
SharedPreferences类提供了一个通用的框架允许你存储和检索原始数据类型的键值对。你可以使用SharedPreferences来保存任何原始数据:booleans, floats, ints, longs, 和 strings.数据通过用户序列保存(即使你的应用程序被杀死)。
User Preferences
Shared preferences 并不严格限制只用于"user preferences," 例如用户选择的手机铃声. 如果你对这部分感兴趣,查阅PreferenceActivity
, 它提供了Activity 框架来创建用户 preferences, 它能够自动进行保存 (using shared preferences).
为了获得SharedPreferences对象,可使用下面的一个或者两个方法:
- 如果你需要多个preferences文件标识符,使用getSharedPreferences()。通过指定的第一个参数来标识名称。
- 如果在Activity中仅使用一个preferences文件,使用getPreferences() 。不支持名称,只能使用一个。
写入值:
- 调用edit()来取得SharedPreferences.Editor对象。
- 使用方法诸如
putBoolean()
和putString()等方法
来添加值。 使用commit()来提交新值。
为了读取值,使用SharedPreferences
的方法,例如getBoolean()
and getString()
在计算器中静音键模式的preference保存例子:
public class Calc extends Activity { public static final String PREFS_NAME = "MyPrefsFile"; @Override protected void onCreate(Bundle state){ super.onCreate(state); . . . // 存储 preferences SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); boolean silent = settings.getBoolean("silentMode", false); setSilent(silent); } @Override protected void onStop(){ super.onStop(); // 我们需要一个 Editor 对象来执行 preference 改变. // 所有这些对象都来自 android.context.Context SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); SharedPreferences.Editor editor = settings.edit(); editor.putBoolean("silentMode", mSilentMode); // Commit the edits! editor.commit(); } }
Using the Internal Storage 使用内部存储器
你可以直接在设备的内部存储器上保存文件。默认情况下保存在内部存储器的数据是私有的外部应用程序不可访问他们。当用户卸载你的应用程序时,这些文件将被移除。
创建和写一个私有文件于内部存储器上:
- 使用文件名和操作模式来调用openFileOutput() 。这将返回一个FileOutputStream对象。
- 使用write()来向文件写入数据。
- 使用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
, and MODE_WORLD_WRITEABLE
.
从内部存储器读数据:
- 以读取文件的名字调用openFileInput()并返回FileInputStream对象 (函数原型:public abstract FileInputStream openFileInput (String name))
- 使用read()从文件读取字节
- 使用close()关闭流。
提示:如果你想在编译时保存静态文件,将文件保存在你工程下的res/raw/目录中。你可以使用openRawResource()打开它,传递R.raw.<filename>资源ID。这个方法返回一个你可用于读取的文件的InputStream(但你无法向原始文件中写入)
Saving cache files 保存缓存文件
如果你想要缓存一些数据,而不是永久储存他们,你应该使用getCacheDir()来打开代表内部存储临时文件的目录的File对象。
当你的设备内部存储空间不足时,安卓可能会删除这些缓存数据来回收空间。然而,你也不应该指望系统会为你清除这些文件。你应该自己维护这些缓存文件在合理的范围内,例如1MB。当用户删除你的应用程序时,这些文件将被移除。
Other useful methods 其他有用的方法
- 获得保存内部文件所在目录的文件系统的绝对路径。
-
- 在内部存储空间中创建(或者打开一个已经存在的)目录。
-
- 删除保存在内部储存中的一个文件
-
- 返回你应用程序保存的当前文件列表
getFilesDir()
getDir()
deleteFile()
fileList()
Using the External Storage 使用外部存储器
每一个安卓兼容的设备都支持可分享你保存的文件的“外部存储器”。它可以是可移动的存储媒介(例如SD 卡)或是内部(不可移动)的存储器。保存在外部存储器上的文件是全局可读的,并且在启用USB大存储来向电脑传输文件时它是可以被修改的。
设备使用部分内部存储作为外部存储之外还提供SD卡插槽。在这种情况下,SD卡不是外部存储的一部分,你的应用程序不能访问它。
警告:如果用户挂载外部存储到电脑或者移除媒介,外部存储器将不可用,并且也没有强制的安全来保存在外部存储上,所有的应用程序能够读写外部存储器上的文件,用户也可以移除他们。
Checking media availability 检查媒介可用性
在外部存储器上做任何事情之前,你应该总是调用 来检查媒介是否可用。媒介可能挂载到电脑上,丢失,只读或者在别的什么状态。下面的例子告诉你该如何做:
boolean mExternalStorageAvailable = false; boolean mExternalStorageWriteable = false; String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { // 我们可以进行读写媒介 mExternalStorageAvailable = mExternalStorageWriteable = true; } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { // 我们只能读媒介 mExternalStorageAvailable = true; mExternalStorageWriteable = false; } else { // 这儿存在一些错误,处于其他的状态,我们所需要知道的,是我们无法进行读写操作 mExternalStorageAvailable = mExternalStorageWriteable = false; }
getExternalStorageState()
方法返回了你可能想要知道的状态,例如媒介正被分享,完全丢失了,或者被不正确的移除了等等。当应用程序访问媒介时,你可以使用状态来告知用户更多的信息。
Accessing files on external storage 在外部存储器上访问文件
如果你的API为8或者更高,使用getExternalFilesDir()来打开代表你存放文件的外部储存器目录。这个方法取得一个 类型参数,来指定你想要访问的子目录,例如DIRECTORY_MUSIC
和 DIRECTORY_RINGTONES
(传递null来接收应用程序根目录)。这个方法会在合适的时候创建目录。通过指定目录类型,你确定媒介是合适的。如果用户删除应用程序,所有它的内容都会被删除。
如果是API7或者更低,使用getExternalStorageDirectory()来打开代表外部根目录的File。你应该像下面这样写入数据:
/Android/data/<package_name>/files/
<package_name>是JAVA风格的包名,如"com.example.android.app
"。如果用户在API8或者更高API删除你的应用程序,所有内容将被删除。
从Media Scanner中隐藏
Include an empty file named.nomedia
in your external files directory (note the dot prefix in the filename). This will prevent Android's media scanner from reading your media files and including them in apps like Gallery or Music.
Saving files that should be shared 保存需要被共享的文件
如果你想要保存文件,他们是与你的应用程序无关的,你应该保存在外部存储器的公有目录中。这些目录处于外部存储器的根目录下,如Music/
, Pictures/
, Ringtones/
等等。
在API 8或者更高,使用getExternalStoragePublicDirectory()传递你想指定的参数,例如DIRECTORY_MUSIC
,DIRECTORY_PICTURES
, DIRECTORY_RINGTONES等等
。这个方法在需要时将会创建目录。
如果你使用API 7或者更低,使用getExternalStoragePublicDirectory()来打开代表根目录的File。然后保存共享的文件到下面的目录中:
Music/
- Media scanner classifies all media found here as user music. 用户音乐Podcasts/
- Media scanner classifies all media found here as a podcast. 播客Ringtones/
- Media scanner classifies all media found here as a ringtone. 手机铃音Alarms/
- Media scanner classifies all media found here as an alarm sound. 闹铃声音Notifications/
- Media scanner classifies all media found here as a notification sound. 通知声音Pictures/
- All photos (excluding those taken with the camera). 图片Movies/
- All movies (excluding those taken with the camcorder). 视频Download/
- Miscellaneous downloads. 下载
Saving cache files 保存缓存文件
如果你的API为8或者更高,使用getExternalFilesDir()来打开代表你存放文件的外部储存器目录。删除程序时,他们会被删除,但是在程序生命周期中,如果你不删除他们,他们也不会自动删除。你应该管理他们,删除不用的。
如果你使用API 7或者更低,使用getExternalStoragePublicDirectory()来打开代表根目录的File,然后写到下面的目录中:
/Android/data/<package_name>/cache/
<package_name>
是Java-style 包名, 例如 "com.example.android.app
".
Using Databases 使用数据库
安卓提供了对于SQLite数据库完全的支持。你创建的数据库可以被你应用程序中的任何类通过名称访问,但在应用程序外部是不可以的。
一种推荐的创建 SQLite数据库的方法是,创建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() 方法。他们都返回代表数据库和提供SQLite方法的 SQLiteDatabase
对象
所有的SQLite查询将返回Cursor 。Cursor是一种机制,你可以导航结果然后获得行与列。你可以使用 SQLiteDatabase
query()
执行查询,它接受一些参数: 查询表名, the projection, 选择参数, columns, 组, 以及其他。对于更加复杂的查询,如包含列别称的查询,你应该使用SQLiteQueryBuilder,它提供了一些便捷方法来构建查询。
SQLite使用的例子,查阅Note Pad and Searchable Dictionary应用。
Database debugging 数据库除错
安卓SDK包括了sqlite3数据库工具,允许你浏览表项,运行SQL语句,执行SQLite数据库的其他有用功能。查阅Examining sqlite3 databases from a remote shell 来获得更多有用信息。
Using a Network Connection 使用网络连接
你可以利用网络()在你拥有的网络服务上来存储或者检索数据。进行网络操作,使用下面这些包中的类: