原文地址:http://developer.android.com/guide/topics/data/data-storage.html
储存选择
安卓为你储存持久化应用数据提供了多种选择。你选择的解决方案决定于你的特殊需求,比如数据是否应该只被你的应用使用还是应该被其他应用或者用户使用,以及你的数据需要多少空间。
你的数据储存选择如下:
Shared Preferences:
通过key-value储存私有的简单的数据
tips:相当于数据库里面的一行,这行很长
Internal Storage
储存私有数据在应用内部储存器
External Storage
储存公开的数据在可分享的外部储存(SDCard)
SQLite Databases
储存结构相同的数据在私有的数据库中
Network Connection
通过你自己的网络服务储存数据在网上
安卓为你提供了一些方式来分享你的私有数据给其他应用:通过content provider。一个content provider是一个可选择的组件,可以暴露读写来操作你的应用数据,受制于你想要强加的关系。关于使用content provider的更多信息,请移步Content Providers文档(http://developer.android.com/guide/topics/providers/content-providers.html)。
一、使用Shared Preferneces
SharedPreferences类提供了一般的框架,允许你储存和取回持久化的私有类型为key-value对的数据。你可以使用SharedPreferences来存储任何私有对象:booleans, floats, ints, longs, and strings。这些数据将通过user sessions来匹配储存(即使你的应用已经被杀死了)。
/×byte(字节型) 1 -128~127
short(短整型) 2 -32768~32767
int(整型) 4 -2147483648~2147483647
long(长整型) 8 -9223372036854775808 ~ 9223372036854775807
float(浮点型) 4 -3.4E38~3.4E38
double(双精度型) 8 -1.7E308~1.7E308
char(字符型) 2 从字符型对应的整型数来划分,其表示范围是0~65535
boolean(布尔型) 1 true或false
×/
为你的应用获取SharedPreferences对象,你要使用下面两个方法之一:
getSharedPreferences() —- 如果你需要储存多个不同名字的preferences文件,第一个参数是preferences的名字。
getPreferences() —- 使用这个如果你只需要一个preferences文件,因为这个会提供一个唯一的preferences文件,不需要提供名字。
tips:Shared preferences不是严格的为了存储“用户的preferences”,比如用户选择的铃声。如果你希望创建用户的preferences,查看PreferenceActivity(http://developer.android.com/reference/android/preference/PreferenceActivity.html),文档提供了Activity的框架来创建用户的preferences,这个PreferenceActivity会自动持久化数据(原理是使用shared preferences)。
写入:
1.调用edit(),获得SharedPreferences.Editor
2.添加key-value键值对,比如:putBoolean()
3.通过commit()提交最新的键值对
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean(“silentMode”, mSilentMode);
读出:
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
boolean silent = settings.getBoolean(“silentMode”, false);
二、使用应用内部储存器(Internal Storage)
你可以直接存储文件在设备的内存,默认情况下,文件被保存到内部储存器,是应用私有的,其他应用不能访问他们。当用户卸载应用,文件被删除。
如何创建和写入一个应用内部储存器:
1.调用openFileOutput (String name, int mode),返回一个FileOutputStream
2.通过write()方法写入文件
3.关闭流(FileOutputStream)
例子:
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 (String name),返回一个FileInputStream。
2.通过read()方法读取
3.关闭输入流
tips:如果你想储存一下静态的文件在你的应用在编译阶段,储存文件在你的工程的res/raw/目录下。你可以通过openRawReSource()方法传入R.raw.使用它们。这些发那个发返回返回一个InputStream,你可以使用它来读取文件,但是不能修改原文件。
保存缓存文件
如果你想缓存一些数据,你应该使用getCacheDir()来打开一个文件代替持久化储存,而不是持久化的存储这些数据。getCacheDir()这个地址是用来储存临时缓存文件的。
当一个设备的应用内部储存不足时,系统可能会删除缓存文件来释放空间。然而,你不应该依赖系统去清理这些缓存文件,你应用总是自己维护缓存文件,使缓存空间保持在一个合理的大小,比如1MB。当用户卸载你的应用的时候,缓存文件会被清除。
其他使用方法:
getFilesDir()
得到你的internal files文件系统目录的绝对路径
getDir()
在你的内部储存空间里面创建或者打开一个存在的目录
deleteFile()
删除一个在内部储存的文件
fileList()
返回当前在应用保存的一列文件
三、使用外部储存
每个安卓独立设备都支持一个共享的外部储存(SDCard),用来存储文件。这个可以是一个可移动的储存媒介(比如SDCard)或者一个内部的储存(不可移动)。文件被存储在外部储存,所有人都可以访问,并且被用户修改,比如通过USB移动文件到电脑上。
警告:外部储存可能会变成难以利用的,如果用户移动外部储存到电脑上或者移除外部储存。所有的应用都可以读写外部储存的文件位置,并且用户可以手工删除它们。
获得外部储存的访问权
为了在外部储存上进行读写操作,你的应用必须获得系统的许可,在manifest里面申明READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE。比如
如果你需要读写文件,那么你只需要请求WRITE_EXTERNAL_STORAGE权限,因为这包含了读的权限。
note:从安卓4.4开始,如果你读写你应用的私有文件,不需要申请权限。更多信息,移步saving files that are app-private(http://developer.android.com/intl/zh-cn/guide/topics/data/data-storage.html#AccessingExtFiles)。
检查媒介可用性
在你操作外部储存之前,你应该调用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()方法返回其他地方,你可能需要检查,比如媒介正在被分享(连接到电脑上),比如外部储存不存在,被移除等等。当你的应用需要用到外部储存的时候,你可以使用这些来提醒用户更多信息。
储存能分享给其他应用的文件
通常,用户通过你的应用获得一个新的文件应该被存为共有的,定位到设备的文件位置,以致其他应用可以访问他们,用户可以更简单在设备间复制。当你这么做的时候,你应该使用公共的分享目录,比如Music/, Pictures/ Ringtones/等等。
tips:从文件扫描中隐藏你的文件
包含一个空的文件名为.nomedia在你的外部储存(注意点在文件名前面),这个阻止媒体扫描在读你的媒体文件的时候,但是可以提供他们给其他应用通过MediaStore content provider。然而,如果你的文件是真的应用私有,你应该把他们存在应用私有目录下。
为了获得适当的获得一个公有目录,调用getExternalStoragePublicDirectory(java.lang.String),传入一个你想获取的目录类型,比如DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTORY_RINGTONES, 或者其他。通过保存你的文件到想匹配的的多媒体类型目录,系统的多媒体扫描可以正确的分类你的文件。(比如:铃声ringtones 出现在系统的设置里面是ringtones,而不是misic)
比如,这里有一些方法来创建新相册的目录,在公共的图片目录:
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;
}
保存文件作为应用私有
如果你要处理文件不打算让其他应用使用,比如graphic textures图形的纹理或者声音效果,你应该使用私有储存目录,通过调用getExternalFilesDir(),这个方法也需要一个type参数来指定一个特殊的子目录类型,比如DIRECTORY_MOVIES,如果你不需要特殊的多媒体目录,传入null来获得应用的私有储存的根目录。
4.4开始,读写应用内的私有文件,不需要申请READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE权限,所以你可以声明权限通过要求最低版本来指定