数据存储

持久化方案

Android系统中主要提供了3种方式用于简单地实现数据持久化功能:文件存储、SharedPreferences存储以及数据库存储。

文件存储

核心技术就是Context类中提供的openFileInput()和openFileOutput()方法,之后就是利用各种流来进行读写操作。

写入数据

  1. 创建openFileOutput()方法,可以用于将数据存储到指定的文件中;
  2. 构建出一个OutputStreamWriter对象,接着再使用OutputStreamWriter构建出一个BufferedWriter对象;
  3. 使用一个use函数,保证在Lambda 表达式中的代码全部执行完之后自动将外层的流关闭,不需要我们手动去关闭流。

文件名不可以包含路径,因为所有的文件都默认存储到/data/data/<package name>/files/目录下。

使用“Device File Explorer”可以查看设备文件。

读取数据

  1. 使用openFileInput()函数进行读取,并返回一个FileInputStream对象;
  2. 构建出一个InputStreamReader对象,接着再使用InputStreamReader构建出一个BufferedReader对象;
  3. 使用一个use函数,通过BufferedReader将文件中的数据一行行读取出来。

SharedPreferences 存储

SharedPreferences是使用键值对的方式来存储数据的。

存储

SharedPreferences文件都是存放在/data/data/<package name>/shared_prefs/目录下的。

  1. 首先需要获取SharedPreferences对象;
  2. 调用SharedPreferences对象的edit()方法获取一个SharedPreferences.Editor对象;
  3. 向SharedPreferences.Editor对象中添加数据,比如添加一个布尔型数据就使用putBoolean()方法,添加一个字符串则使用putString()方法,以此类推;
  4. 调用apply()方法将添加的数据提交,从而完成数据存储操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MainActivity : AppCompatActivity() { 

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
saveButton.setOnClickListener {
val editor = getSharedPreferences("data", Context.MODE_PRIVATE).edit()
editor.putString("name", "Tom")
editor.putInt("age", 28)
editor.putBoolean("married", false)
editor.apply()
}
}

}

读取

  1. 首先通过getSharedPreferences()方法得到SharedPreferences对象;
  2. 然后分别调用它的getString()、getInt()和getBoolean()等方法即可获取数据。

SQLite 数据库存储

安装Database Navigator插件工具。

创建数据库

提供了一个SQLiteOpenHelper帮助类,借助这个类可以非常简单地对数据库进行创建和升级。

继承SQLiteOpenHelper抽象类,重写SQLiteOpenHelper中两个抽象方法:onCreate()和onUpgrade();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MyDatabaseHelper(val context: Context, name: String, version: Int) : 
SQLiteOpenHelper(context, name, null, version) {

private val createBook = "create table Book (" +
" id integer primary key autoincrement," +
"author text," +
"price real," +
"pages integer," +
"name text)"

override fun onCreate(db: SQLiteDatabase) {
db.execSQL(createBook)
Toast.makeText(context, "Create succeeded", Toast.LENGTH_SHORT).show()
}

override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("drop table if exists Book")
db.execSQL("drop table if exists Category")
onCreate(db)
}

}

添加数据

操作数据有两种方案,一种是使用SQL语句,一种是使用Android提供的封装函数。

  • 使用SQL语句:除了查询数据的时候调用的是SQLiteDatabase的rawQuery()方法,其他操作都是调用的execSQL()方法。

  • 使用SQLiteDatabase对象,借助这个对象可以对数据进行CRUD操作:

    1. SQLiteDatabase中提供了一个insert()方法,专门用于添加数据;

    2. SQLiteDatabase中提供了一个非常好用的update()方法,用于对数据进行更新;

    3. SQLiteDatabase中提供了一个delete()方法,专门用于删除数据;

    4. SQLiteDatabase中还提供了一个query()方法用于对数据进行查询,这个方法的参数非常复杂,最短的一个方法重载也需要传入7个参数。

      QQ_1737171509823

使用事务

事务的特性可以保证让一系列的操作要么全部完成,要么一个都不会完成

  1. 首先调用SQLiteDatabase的beginTransaction()方法开启一个事务;
  2. 然后在一个异常捕获的代码块中执行具体的数据库操作;
  3. 当所有的操作都完成之后,调用setTransactionSuccessful()表示事务已经执行成功了;
  4. 最后在finally代码块中调用endTransaction()结束事务。

升级数据库的最佳写法的本质就是使用小于等于符号判定版本,并写若干个if语句。


Kotlin课堂

简化SharedPreferences 的用法

1
2
3
4
5
6
7
8
9
10
fun SharedPreferences.edit(block: SharedPreferences.Editor.() -> Unit) { 
val editor = edit()
editor.block()
editor.apply()
}
getSharedPreferences("data", Context.MODE_PRIVATE).edit {
putString("name", "Tom")
putInt("age", 28)
putBoolean("married", false)
}

其实Google提供的KTX扩展库中已经包含了上述 SharedPreferences的简化用法。

简化ContentValues 的用法

在Kotlin中使用A to B这样的语法结构会创建一个Pair对象。

使用vararg关键字,指可变参数列表,我们允许向这个方法传入任意多个参数,这些参数都会被赋值到使用vararg声明的这一个变量上面,然后使用for-in循环可以将传入的所有参数遍历出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fun cvOf(vararg pairs: Pair<String, Any?>): ContentValues { 
val cv = ContentValues()
for (pair in pairs) {
val key = pair.first
val value = pair.second
when (value) {
is Int -> cv.put(key, value)
is Long -> cv.put(key, value)
is Short -> cv.put(key, value)
is Float -> cv.put(key, value)
is Double -> cv.put(key, value)
is Boolean -> cv.put(key, value)
is String -> cv.put(key, value)
is Byte -> cv.put(key, value)
is ByteArray -> cv.put(key, value)
null -> cv.putNull(key)
}
}
return cv
}
val values = cvOf("name" to "Game of Thrones", "author" to "George Martin",
"pages" to 720, "price" to 20.85)
db.insert("Book", null, values)

Kotlin中的Smart Cast功能。比如when语句进入Int条件分支后,这个条件下面的value会被自动转换成Int类型,而不再是Any?类型。

KTX库中也提供 了一个具有同样功能的contentValuesOf()方法:

1
2
3
val values = contentValuesOf("name" to "Game of Thrones", "author" to "George Martin", 
"pages" to 720, "price" to 20.85)
db.insert("Book", null, values)