SharePreferences
SharePreferences适合用来保存相对较小的键值集合,比如应用程序的配置文件,它本质是存放在/data/data/[包名]/shared_prefs文件夹下的xml文件。
你可以通过调用两种方式之一来创建新的共享首选项文件或访问现有的文件:
getSharedPrefernces(String name, int mode)
如果你需要按照你指定的名称识别的多个共享首选项文件,请使用此方法。 第一个参数表示目标首选项文件,第二个参数表示操作模式。getPreferences(int mode)
获得SharedPreferences对象,这个对象所操作的首选项文件对该Activity是私有的,所创建的首选项名称就是该Activity的类名。
操作模式有三种:
MODE_PRIVATE
: 默认的模式,创建的文件只能被调用者引用访问。常量:0MODE_WORLD_READABLE
: 该模式下创建的文件是全局可读的,这样做是非常危险的,容易导致应用出现安全漏洞,你应该使用更加正式的交互机制例如ContentProvider
,BroadcastReceiver
以及Service
。常量:1MODE_WORLD_WRIEABLE
: 该模式下创建的文件是全局可写的,后面的话跟上面一样。常量:2
要写入共享首选项文件, 请通过对您的 SharedPreferences
调用 edit()
来创建一个 SharedPreferences.Editor
对象
从首选项文件中获取数据:
SharedPreferences preferences = getSharedPreferences("FileName", 0);
int age = preferences.getInt("age", 0);
String name = preferences.getString("name", null);
从首选项中输入数据:
SharedPreferences preferences = getSharedPreferences("FileName", 0);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("name", "thanatos");
editor.putInt("age", 18);
editor.commit();
File
File
对象适合按照从开始到结束的顺序不跳过地读取或写入大量数据。 例如,它适合于图像文件或通过网络交换的任何内容
内部储存和外部储存
所有 Android 设备都有两个文件存储区域:“内部”和“外部”存储。这些名称在 Android 早期产生,当时大多数设备都提供内置的非易失性内存(内部存储),以及移动存储介质,比如微型 SD 卡(外部存储)。一些设备将永久性存储空间划分为“内部”和“外部”分区,即便没有移动存储介质,也始终有两个存储空间,并且无论外部存储设备是否可移动,API 的行为均一致。以下列表汇总了关于各个存储空间的实际信息。
-
内部储存
- 它始终可用
- 默认情况下只有你的应用可以访问此处保存的文件
- 当用户卸载你的应用时,系统会从内部储存中删除你的应用的所用文件
-
外部存储:
- 它并非始终可用,因为用户可采用 USB 存储的形式装载外部存储,并在某些情况下会从设备中将其删除
- 它是全局可读的,因此此处保存的文件可能不受您控制地被读取
- 当用户卸载您的应用时,只有在您通过
getExternalFilesDir()
将您的应用的文件保存在目录中时,系统才会从此处删除您的应用的文件
Note:尽管应用默认安装在内部存储中,但您可在您的宣示说明中指定
android:installLocation
属性,这样您的应用便可安装在在外部存储中。 当 APK 非常大且它们的外部存储空间大于内部存储时,用户更青睐这个选择。 如需了解详细信息,请参阅应用安装位置。
要向外部存储写入信息,你必须在清单文件中请求WRITE_EXTERNAL_STORAGE
权限,它也隐含读取外部储存的权限
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
将文件保存在内部储存中
通过调用下面两种方法之一来获得相应目录:
getFilesDir()
:对应的目录是/data/data/[程序包名]/files,上下文有提供两个方法openFileInput(String name)
和openFileOutput(String name, int mode)
来在这个目录下读写文件。getCacheDir()
:应用临时缓存文件的内部目录,对应目录是/data/data/[程序包名]/cache 。 务必删除所有不再需要的文件并对在指定时间使用的内存量实现合理大小限制,比如,1MB。 如果在系统即将耗尽存储,它会在不进行警告的情况下删除缓存文件。
将文件保存在外部储存中
在访问它之前,你应始终确认其容量。 可以通过调用 getExternalStorageState()
查询外部存储状态,状态有如下几种(它们的常量值都是字符串):
MEDIA_UNKNOWN
无法识别MEDIA_REMOVED
已删除或外部存储设备不在MEDIA_UNMOUNTED
储存存在但是没有安装MEDIA_CHECKING
正在执行硬盘检查MEDIA_NOFS
储存设备存在但是是空白的或者是因为是不支持的文件系统MEDIA_MOUNTED
已安装MEDIA_MOUNTED_READ_ONLY
已安装并且只读MEDIA_SHARED
MEDIA_BAD_REMOVAL
在外部存储设备被卸载之前被移除MEDIA_UNMOUNTABLE
储存存在但是不能安装,典型情况是外部储存设备已损坏
// ---- 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(String type)
方法来获取外部存储上的相应公共文件,类型参数有DIRECTORY_MUSIC
或DIRECTORY_PICTRUES
等
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), "Best.mp4");
调用上下文对象的getExternalFilesDir(String type)
方法获取你应用专用文件下的传递指示的目录类型的名称,一般是/storage/Android/data/[应用包名]/files/[指定文件类型的目录],如果type值传递null
,则返回专有文件的根目录,也就是/storage/Android/data/[应用包名]/files,getExternalCacheDir()
对应的目录为/storage/Android/data/[应用包名]/cache
Note:当用户卸载您的应用时,Android 系统会删除以下各项:
- 您保存在内部存储中的所有文件
- 您使用
getExternalFilesDir()
保存在外部存储中的所有文件。
但是,您应手动删除使用
getCacheDir()
定期创建的所有缓存文件并且定期删除不再需要的其他文件。
在SQL数据库中保存数据
SQL 数据库的主要原则之一是架构:数据库如何组织的正式声明。 架构体现用于创建数据库的 SQL 语句,一般都会伴随者一个类,实体类,伴随类,契约类(原意contract class)。契约类是用于定义 URI、表格和列名称的常数的容器。 契约类允许您跨同一软件包中的所有其他类使用相同的常数。
public final class UserContract {
public UserContract() {
}
public abstract static class UserEntry implements BaseColumns{
public static final String TABLE_NAME = "User";
public static final String COLUMN_NAME = "name";
public static final String COLUMN_PASSWORD = "password";
public static final String CREATE_TABLE = String.format(
"CREATE TABLE %s(" +
"%s INTEGER PRIMARY KEY AUTOINCREMENT, " +
"%s VARCHAR(20) NOT NULL," +
"%s VARCHAR(20) NOT NULL)",
TABLE_NAME, _ID, COLUMN_NAME, COLUMN_PASSWORD
);
public static final String DELETE_TABLE = String.format(
"DROP TABLE IF EXIST %s", TABLE_NAME
);
}
}
Note:通过实现
BaseColumns
接口,您的内部类可继承调用的主键字段_ID
,某些 Android 类(比如光标适配器)将需要内部类拥有该字段。 这并非必需项,但可帮助您的数据库与 Android 框架协调工作。
定义好了数据库表的“外观”之后,我们还需要可以对数据库执行操作的对象。SQLiteOpenHelper
类中就提供了需要的API。当你使用此类获取对数据库的引用时,系统将只在需要之时而不是应用启动过程中执行可能长期运行的操作:创建和更新数据库。 你只需调用 getWritableDatabase() 或 getReadableDatabase()。由于它们可能长期运行,因此最好在后台线程中调用 getWritableDatabase()
或 getReadableDatabase()
使用一个子类继承SQLiteOpenHelper
实现一些回调方法来针对性的对契约类执行CURD操作
public class DBHelper extends SQLiteOpenHelper{
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "example.db";
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**
* 当检测到没有database_name定义的database时才会调用这个方法来创建database
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(UserContract.UserEntry.CREATE_TABLE);
}
/**
* database_version定义的版本号会传入SQLite里,当database_version的版本
* 增加的时候,数据库对比版本号就会调用这个方法
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(UserContract.UserEntry.DELETE_TABLE);
onCreate(db);
}
}