持久化简介
数据持久化就是指将内存中的数据保存到存储设备中,保证手机或者计算机关机的情况下数据不会丢失。
文件存储
使用文件存储的方式存储数据,不会对存储的内容做任何格式化处理,所有的数据都是原封不动的保存到文件中,因此适合比较简单的文本或者二进制数据;
如果要存储较为复杂的结构化数据,最好定义一套格式规范,方便从文件中解析数据;
将数据存储到文件中
创建用于保存数据的方法:
public static boolean saveAsFile(Context context, String fileName,String content){
try {
FileOutputStream fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos));
writer.write(content);
writer.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
在Context类中提供了一个openFileOutput的方法用于获取文件输出流。
openFileOutput方法有两个参数,第一个参数是目标文件的文件名,第二个是文件的操作模式;
文件名参数中不可包含路径,因为这里生成的文件默认是在/data/data/<package>/files/目录下的;
操作模式在Android10中仅剩两种,一种是“MODE_PRIVATE”,即如果存在同名文件则覆盖,另一种是"MODE_APPEND",即如果存在同名文件则在文件末尾追加新的数据,不存在则新建;
从文件中读取数据
创建用于读取数据的方法:
public static String loadFromFile(Context context, String fileName){
StringBuilder content = new StringBuilder();
try {
FileInputStream fis = context.openFileInput(fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
while (reader.read() != -1){
content.append(reader.readLine());
}
return content.toString();
}catch (IOException e){
e.printStackTrace();
return null;
}
}
在Context类中提供了一个openFileInput的方法用于获取文件输入流,然后读取文件。
SharedPreferences存储
SharedPreferences使用键值对的方式来存储数据,当保存一条数据的时候,需要给这个数据提供一个对应的键,之后在读取的时候可以通过这个键把值取出来。
将数据保存到SharedPreferences中
在Android中提供了两种方式获取SharedPreferences对象:
-
Context中的getSharedPreferences方法
该方法有两个参数,第一个参数用于指定SharedPreferences文件的名称,如果不存在就会创建,SharedPreferences文件默认存放在/data/data/<package name>/shared_prefs/目录下;
第二个参数是用于指定操作模式,当前(Android10)仅有一个模式“MODE_PRIVATE”;
-
Activity中的getPreferences方法
该方法仅接收一个操作模式参数,在Activity中的getPreferences会默认文件名为当前Activity的类名。
使用步骤有三:
- 调用SharedPreferences对象的edit方法获取SharedPreferences.Editor对象;
- 向SharedPreferences.Editor对象中加入数据;
- 调用SharedPreferences.Editor对象的apply方法,提交数据,完成数据存储操作;
在Activity中调用:
//保存数据
SharedPreferences.Editor editor = getSharedPreferences("info", Context.MODE_PRIVATE).edit();
editor.putString("username", "root");
editor.putInt("days", 21);
editor.putBoolean("isVIP", false);
editor.apply();
从SharedPreferences中读取数据
在Activity中调用:
//读取数据
SharedPreferences sharedPreferences = getSharedPreferences("info", MODE_PRIVATE);
String username = sharedPreferences.getString("username","无数据");
int day = sharedPreferences.getInt("days", -1);
boolean isVip = sharedPreferences.getBoolean("isVIP", false);
Log.i(TAG, "onCreate: username:" + username +", day:" + day + ",isVip" + isVip);
SQLite存储
SQLite是轻量级关系型数据库,运算速度快,占用资源少,支持标准SQL语法,遵循ACID原则。
创建数据库
SQLiteOpenHelper有两个很重要的方法:
-
getReadableDatabase()
创建或打开一个只读的数据库,并返回一个可对数据库操作的对象;
-
getWritableDatabase()
创建或者打开一个可写数据库,并返回一个可对数据库操作的对象,但是如果当前数据库处于不可写入状态(如存储空间已满)将抛出异常;
创建SQLiteOpenHelper一般使用四个参数的构造方法重写:
-
第一个参数
Context获取上下文环境;
-
第二个参数
数据库名;
-
第三个参数
自定义的Cursor,一般为null;
-
第四个参数
版本号,用于数据库的升级操作;
数据库文件会保存在/data/data/<package name>/databases/目录下。
创建自定义类继承SQLiteOpenHelper,重写onCreate()和onUpgrade():
public class FLCDBHelper extends SQLiteOpenHelper {
private final String TAG = "FLCDBHelper";
private final String CREATE_BOOK_TABLE = "create table Book(" +
"id integer primary key autoincrement," +
"author text," +
"price real," +
"pages integer," +
"name text)";
public FLCDBHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(CREATE_BOOK_TABLE);
Log.i(TAG, "onCreate: 创建表Book");
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
指定数据库名为“Book.db”且版本号为“1”:
private void createDB(){
FLCDBHelper helper = new FLCDBHelper(this, "Book.db", null,1);
helper.getWritableDatabase();
}
升级数据库
如果数据库的版本没有改变,那么就不会调用onUpgrade方法,修改创建数据库时的版本号:
private void createDB(){
FLCDBHelper helper = new FLCDBHelper(this, "Book.db", null,2);
helper.getWritableDatabase();
}
重写onUpgrade方法:
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL("drop table if exists Book");
onCreate(sqLiteDatabase);
}
添加数据
调用SQLiteOpenHelper的getReadableDatabase()和getWritableDatabase()都会返回一个SQLiteDatabase对象,可以根据这个对象对数据库进行CRUD操作。
SQLiteDatabase的insert()方法用于添加数据,该方法有三个参数:
-
第一个参数
要插入数据的表名;
-
第二个参数
用于在未指定添加数据的情况下为某些值自动赋值为NULL,一般取值为null;
-
第三个参数
ContentValues对象,通过put()方法添加数据,put中输入的为键值对,键为列名,值为要插入的数据;
示例代码:
private void insertDefaultBook(SQLiteDatabase database){
ContentValues values = new ContentValues();
values.put("author", "Casablanca");
values.put("price", 10.10);
values.put("pages", 60);
values.put("name", "Casablanca");
database.insert("Book", null, values);
}
更新数据
通过SQLiteDatabase对象可获取update()方法,该方法用于更新数据。
update方法有四个参数:
-
第一个参数
表名,用于指出要更新哪个表的数据;
-
第二个参数
ContentValues,用于保存要更新的数据;
-
第三个参数
约束条件,条件的取值用“?”代替;
-
第四个参数
约束条件的取值;
如果第三四个参数为null,则会更新所有行。
示例代码:
private void updateDefaultBook(SQLiteDatabase database){
ContentValues values = new ContentValues();
values.put("price", 25.00);
database.update("Book", values, "name = ?", new String[]{"Casablanca"});
}
删除数据
通过SQLiteDatabase对象可获取delete方法用于删除数据。
delete方法有三个参数:
-
第一个参数
表名,指出要删除数据的表名;
-
第二个参数
约束条件,条件的取值用“?”代替;
-
第三个参数
约束条件的取值;
示例代码:
private void deleteDefaultBook(SQLiteDatabase database){
database.delete("Book", "name = ?", new String[]{"Casablanca"});
}
查询数据
通过SQLiteDatabase对象可获取query方法用于查询数据。
最短的query也要7个参数:
query()方法参数 | 对应的SQL部分 | 描述 |
---|---|---|
table | from table_name | 指定查询的表名 |
columns | select col1,col2,… | 指定查询的列名 |
selection | where col = value | 指定where的约束条件 |
selectionArgs | 为where中的占位符提供具体的值 | |
groupBy | group by col | 指定需要group by的列 |
having | having col = value | 对group by的结果进一步约束 |
orderBy | order by col1,col2,… | 指定查询结果的排列方式 |
示例代码:
private String queryDefaultBook(SQLiteDatabase database){
Cursor cursor = database.query("Book", null, "name = ?", new String[]{"Casablanca"}, null, null, null);
StringBuilder res = new StringBuilder();
if (cursor.moveToFirst()){
do {
String author = cursor.getString(cursor.getColumnIndex("author"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
String name = cursor.getString(cursor.getColumnIndex("name"));
res.append("[name=").append(name)
.append(",price=").append(price)
.append(",pages=").append(pages)
.append(",author=").append(author)
.append("]");
}while (cursor.moveToNext());
}
cursor.close();
return res.toString();
}