lesson 5保存数据
1 保存键值集
注意:SharedPreferences API 仅用于读写键值对,您不得将其与 Preference API 混淆,后者帮助您为您的应用设置构建用户界面(尽管它们使用 SharedPreferences 作为其实现以保存应用设置)。 有关使用 Preference API 的信息,请参阅设置指南。
1.1 获得SharedPreferences
- getSharedPreferences() Context对象调用
- getPreferences() Activity对象调用
1.2 写入内容步骤
要写入共享首选项文件, 请通过对您的 SharedPreferences 调用 edit() 来创建一个 SharedPreferences.Editor。
传递您想要使用诸如 putInt() 和 putString() 方法写入的键和值。然后调用 commit() 以保存更改。例如:
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(getString(R.string.saved_high_score), newHighScore);
editor.commit();
1.3 读出内容步骤
要从共享首选项文件中检索值,请调用诸如 getInt() 和 getString() 等方法,为您想要的值提供键,并根据需要提供要在键不存在的情况下返回的默认值。 例如:
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
int defaultValue = getResources().getInteger(R.string.saved_high_score_default);
long highScore = sharedPref.getInt(getString(R.string.saved_high_score), defaultValue);
2 保存文件
2.1 内部存储和外部存储的定义和区别
内部存储
: 设备都提供内置的非易失性内存
特点:
- 它始终可用。
- 默认情况下只有您的应用可以访问此处保存的文件。
- 当用户卸载您的应用时,系统会从内部存储中删除您的应用的所有文件。
当您希望确保用户或其他应用均无法访问您的文件时,内部存储是最佳选择。
内部存储
: 移动存储介质,比如微型 SD 卡
特点:
- 它并非始终可用,因为用户可采用 USB 存储的形式装载外部存储,并在某些情况下会从设备中将其删除。
- 它是全局可读的,因此此处保存的文件可能不受您控制地被读取。
- 当用户卸载您的应用时,只有在您通过 getExternalFilesDir() 将您的应用的文件保存在目录中时,系统才会从此处删除您的应用的文件。
对于无需访问限制以及您希望与其他应用共享或允许用户使用电脑访问的文件,外部存储是最佳位置。
提示:尽管应用默认安装在内部存储中,但您可在您的宣示说明中指定 android:installLocation 属性,这样您的应用便可安装在在外部存储中。 当 APK 非常大且它们的外部存储空间大于内部存储时,用户更青睐这个选择。 如需了解详细信息,请参阅应用安装位置。
2.2 获取外部存储的权限
写入权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
如果您的应用需要读取外部存储(但不向其写入信息),那么您将需要声明 READ_EXTERNAL_STORAGE 权限。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
但是,如果您的应用使用 WRITE_EXTERNAL_STORAGE 权限,那么它也隐含读取外部存储的权限。
您无需任何权限,即可在内部存储中保存文件。 您的应用始终具有在其内部存储目录中进行读写的权限。
2.3 将文件保存在内部存储中
在内部存储中保存文件时,您可以通过调用以下两种方法之一获取作为 File 的相应目录:
2.3.1 获取内部存储File的目录
getFilesDir()
: 返回表示您的应用的内部目录的 File 。
getCacheDir()
: 返回表示您的应用临时缓存文件的内部目录的 File 。 务必删除所有不再需要的文件并对在指定时间您使用的内存量实现合理大小限制,比如,1MB。 如果在系统即将耗尽存储,它会在不进行警告的情况下删除您的缓存文件。
2.3.2 创建文件
第一种方法:使用 File() 构造函数
File file = new File(context.getFilesDir(), filename);
第二种方法: 调用 openFileOutput() [api 注释: Creates the file if it doesn’t already exist.] 获取写入到内部目录中的文件的 FileOutputStream 。例如,此处显示如何向文件写入一些文本:
String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;
try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
如果您需要缓存某些文件,您应改用 createTempFile()。例如,以下方法从 URL 提取文件名并在您的应用的内部缓存目录中以该名称创建文件:
public File getTempFile(Context context, String url) {
File file;
try {
String fileName = Uri.parse(url).getLastPathSegment();
file = File.createTempFile(fileName, null, context.getCacheDir());
catch (IOException e) {
// Error while creating file
}
return file;
}
2.4 将文件保存在外部存储中
2.4.1 检查外部存储是否可用
/* 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;
}
2.4.2 外部存储分类
公共文件
- 应供其他应用和用户自由使用的文件。
- 当用户卸载您的应用时,用户应仍可以使用这些文件。
例如,您的应用拍摄的照片或其他已下载的文件。
私有文件
- 本属于您的应用且应在用户卸载您的应用时删除的文件。尽管这些文件在技术上可被用户和其他应用访问(因为它们在外部存储上),它们是实际上不向您的应用之外的用户提供值的文件。
- 当用户卸载您的应用时,系统会删除应用外部专用目录中的所有文件。
例如,您的应用下载的其他资源或临时介质文件。
如果您要使用外部存储上的公共文件,请使用 getExternalStoragePublicDirectory() 方法获取表示外部存储上相应目录的 File 。该方法使用指定 您想要保存以便它们可以与其他公共文件在逻辑上组织在一起的文件类型的参数,比如 DIRECTORY_MUSIC 或 DIRECTORY_PICTURES。 例如:
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() *获取相应的目录并向其传递指示您想要的目录类型的名称。 通过这种方法创建的各个目录将添加至封装您的应用的所有外部存储文件的父目录,当用户卸载您的应用时,系统会删除这些文件。
例如,您可以使用以下方法来创建个人相册的目录:
public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app's private pictures directory.
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
如果没有适合您文件的预定义子目录名称,您可以改为调用 getExternalFilesDir() 并传递 null。这将返回外部存储上您的应用的专用目录 的根目录。
切记,getExternalFilesDir() 在用户卸载您的应用时删除的目录内创建目录。如果您正保存的文件应在用户卸载您的应用后仍然可用—比如,当您的应用是照相机并且用户要保留照片时—您应改用 getExternalStoragePublicDirectory()。
无论您对于共享的文件使用 getExternalStoragePublicDirectory() 还是对您的应用专用文件使用 getExternalFilesDir() ,您使用诸如
DIRECTORY_PICTURES
的 API 常数提供的目录名称非常重要。 这些目录名称可确保系统正确处理文件。 例如,保存在 DIRECTORY_RINGTONES 中的文件由系统介质扫描程序归类为铃声,而不是音乐。