一、数据持久化

数据持久化就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或计算机关机的情况下,这些数据仍然不会丢失。

保存在内存中的数据是处于瞬时状态的,而保存在存储设备中的数据是处于持久状态的。持久化技术提供了一种机制,可以让数据在瞬时状态和持久状态之间进行转换。

Android系统中主要提供了3种方式用于简单地实现数据持久化功能:

  • 文件存储;
  • SharedPreferences存储;
  • 数据库存储;

二、文件存储

文件存储是Android中最基本的数据存储方式,它不对存储的内容进行任何格式化处理,所有数据都是原封不动地保存到文件当中的,因而它比较适合存储一些简单的文本数据或二进制数据。

如果你想使用文件存储的方式来保存一些较为复杂的结构化数据,就需要定义一套自己的格式规范,方便之后将数据从文件中重新解析出来。

Context类中提供了一个openFileOutput()方法,可以用于将数据存储到指定的文件中。

所有的文件会默认存储到​​/data/data/<package name>/files/​​目录下。示例写法如下:

fun save(inputText:String) {
try{
val output = openFileOutput("data",Context.MODE_PROVATE)
val writer = BufferedWriter(OutputStreamWriter(output))
writer.use{
it.write(inputText)
}
}catch(e:IOException){
e.printStackTrace()
}
}

​openFileOutput​​中的data是文件名;

Context类中还提供了一个openFileInput()方法,用于从文件中读取数据。

它会自动到/data/data//files/目录下加载文件,并返回一个FileInputStream对象,得到这个对象之后,再通过流的方式就可以将数据读取出来了。示例写法如下:

fun load() : String{
val content == StringBuilder()
try{
val input = openFileInput("data")
val reader = BufferedReader(InputStreamReader(input))
reader.use{
reader.forEachLine{
content.append(it)
}
}
}catch(e:IOException){
e.printStackTrace()
}

return content.toString()
}

​openFileInput​​中的data是文件名;


实例展示:点击按钮,保存文本【文件存储】,马上读取,并用Toast显示

package com.example.helloworld

import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle

import android.widget.* //引入widget组件包
import java.io.*

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

//匹配布局里的按钮
val button = findViewById<Button>(R.id.button)
//给按钮添加监听器
button.setOnClickListener{
save("文件存储") //写入文件存储

Toast.makeText(this,load(),Toast.LENGTH_SHORT).show(); //读取文件存储
}
}
//----------------------------------------------------------------------------
fun save(inputText:String) {
try{
val output = openFileOutput("data",Context.MODE_PRIVATE)
val writer = BufferedWriter(OutputStreamWriter(output))
writer.use{
it.write(inputText)
}
}catch(e: IOException){
e.printStackTrace()
}
}
//----------------------------------------------------------------------------
fun load():String{
val content = StringBuilder()
try {
val input = openFileInput("data")
val reader = BufferedReader(InputStreamReader(input))
reader.use {
reader.forEachLine {
content.append(it)
}
}
}catch (e:IOException){
e.printStackTrace()
}

return content.toString()
}

}

Android第八课-----数据存储_java


三、SharedPreferences存储

​SharedPreferences​​是使用键值对的方式来存储数据的,也就是说,当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通过这个键把相应的值取出来。

​SharedPreferences​​还支持多种不同的数据类型存储,如果存储的数据类型是整型,那么读取出来的数据也是整型的;如果存储的数据是一个字符串,那么读取出来的数据仍然是字符串。

向SharedPreferences文件中存储数据了,主要可以分为3步实现:

  • 调用SharedPreferences对象的edit()方法获取一个SharedPreferences.Editor对象;
  • 向SharedPreferences.Editor对象中添加数据,比如添加一个布尔型数据就使用putBoolean()方法,添加一个字符串则使用putString()方法,以此类推;
  • 调用apply()方法将添加的数据提交,从而完成数据存储操作;
//SharedPreferences存储
val editor = getSharedPreferences("data",Context.MODE_PRIVATE).edit()
editor.putString("name","张三")
editor.putInt("age",28)
editor.putBoolean("married",false)
editor.apply()

SharedPreferences对象中提供了一系列的get方法,用于对存储的数据进行读取,每种get方法都对应了SharedPreferences.Editor中的一种put方法。
比如读取一个布尔型数据就使用getBoolean()方法,读取一个字符串就使用getString()方法。

示例写法如下:

//SharedPreferences读取
val prefs = getSharedPreferences("data",Context.MODE_PRIVATE)
val name = prefs.getString("name","")
val age = prefs.getInt("age",0)
val married = prefs.getBoolean("married",false)

四、数据库存储

SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百KB的内存就足够了,因而特别适合在移动设备上使用。

SQLite不仅支持标准的SQL语法,还遵循了数据库的ACID事务,所以只要你以前使用过其他的关系型数据库,就可以很快地上手SQLite。而SQLite又比一般的数据库要简单得多,它甚至不用设置用户名和密码就可以使用。

Android正是把这个功能极为强大的数据库嵌入到了系统当中,使得本地持久化的功能有了一次质的飞跃。


创建数据库
Android为了让我们能够更加方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类可以非常简单地对数据库进行创建和升级。示例写法如下:

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) {
}

}

更新数据库

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)"

private val createCategory = "create table Category (" +
"id integer primary key autoincrement," +
"category_name text," +
"category_code integer)"

override fun onCreate(db: SQLiteDatabase) {
db.execSQL(createBook)
db.execSQL(createCategory)
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)
}

}


SQLiteDatabase中提供了一个insert()方法,专门用于添加数据。它接收3个参数:

  • 第一个参数是表名,我们希望向哪张表里添加数据,这里就传入该表的名字;
  • 第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传入null即可;
  • 第三个参数是一个ContentValues对象,它提供了一系列的put()方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。

示例写法如下:

val dbHelper = MyDatabaseHelper(this, "BookStore.db", 2)
val db = dbHelper.writableDatabase
val values1 = ContentValues().apply {
// 开始组装第一条数据
put("name", "The Da Vinci Code")
put("author", "Dan Brown")
put("pages", 454)
put("price", 16.96)
}
db.insert("Book", null, values1) // 插入一条数据


SQLiteDatabase中提供了一个delete()方法,专门用于删除数据。它接收3个参数:

  • 第一个参数仍然是表名,这个没什么好说的;
  • 第二、第三个参数用于约束删除某一行或某几行的数据,不指定的话默认会删除所有行。

示例写法如下:

val dbHelper = MyDatabaseHelper(this, "BookStore.db", 2)
val db = dbHelper.writableDatabase
db.delete("Book", "pages > ?", arrayOf("500"))


SQLiteDatabase中提供了一个非常好用的update()方法,用于对数据进行更新。它接收4个参数:

  • 第一个参数和insert()方法一样,也是表名,指定更新哪张表里的数据;
  • 第二个参数是ContentValues对象,要把更新数据在这里组装进去;
  • 第三、第四个参数用于约束更新某一行或某几行中的数据,不指定的话默认会更新所有行。

示例写法如下:

val dbHelper = MyDatabaseHelper(this, "BookStore.db", 2)            
val db = dbHelper.writableDatabase
val values = ContentValues()
values.put("price", 10.99)
db.update("Book", values, "name = ?", arrayOf("The Da Vinci Code"))

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

Android第八课-----数据存储_sqlite_02


查询Book表中所有数据的示例写法:

val dbHelper = MyDatabaseHelper(this, "BookStore.db", 2)
val db = dbHelper.writableDatabase
// 查询Book表中所有的数据
val cursor = db.query("Book", null, null, null, null, null, null)
if (cursor.moveToFirst()) {
do {
// 遍历Cursor对象,取出数据并打印
val name = cursor.getString(cursor.getColumnIndex("name"))
val author = cursor.getString(cursor.getColumnIndex("author"))
val pages = cursor.getInt(cursor.getColumnIndex("pages"))
val price = cursor.getDouble(cursor.getColumnIndex("price"))
Log.d("MainActivity", "book name is $name")
Log.d("MainActivity", "book author is $author")
Log.d("MainActivity", "book pages is $pages")
Log.d("MainActivity", "book price is $price")
} while (cursor.moveToNext())
}
cursor.close()

使用SQL操作数据库
当然我们也可以使用SQL语句来完成前面的所有功能。

添加数据的方法如下:

db.execSQL(
“insert into Book (name, author, pages, price) values(?, ?, ?, ?), arrayOf("The Da Vinci Code", "Dan Brown", "454", "16.96")
)

删除数据的方法如下:

db.execSQL("delete from Book where pages > ?", arrayOf("500"))

更新数据的方法如下:

db.execSQL("update Book set price = ? where name = ?", arrayOf("10.99", "The Da Vinci Code"))

查询数据的方法如下:

val cursor = db.rawQuery("select * from Book", null)