Android-持久化数据存储

一 SharedPreferences

  • SharedPreferences是使用键值对的方式来存储数据的。数据保存在一个xml文件中,在/data/data/<package_name>/shared_prefs目录下。
  • 要想使用SharedPreferences存储数据,首先需要获取SharedPreferences对象。Android提供了以下两种方法用于得到SharedPreferences对象。
  1. Context类中的getSharedPreferences()方法:

此方法接收两个参数:第一个参数用于指定SharedPreferences文件的名称,如果指定的文件不存在则会创建一个;第二个参数用于指定操作模式,目前只有默认的MODE_PRIVATE这一种模式可选,其它已废弃,MODE_PRIVATE表示只有当前的应用程序才可以对这个SharedPreferences文件进行读写。

  1. Activity类中的getPreferences()方法

这个方法和第一种类似,不过它只接收一个操作模式参数,因为使用这个方法时会自动将当前Activity的类名作为SharedPreferences的文件名。

  • 得到SharedPreferences对象之后,就可以开始向SharedPreferences文件中存储数据了,主要步骤如下:
  1. 调用SharedPreferences对象的edit()方法获取一个SharedPreferences.Editor对象。
  2. 向SharedPreferences.Editor对象中添加数据,比如添加一个布尔型数据就使用putBoolean()方法。
  3. 调用apply()方法将添加的数据提交,从而完成数据存储操作。
sendBtn.setOnClickListener {
           val editor = getSharedPreferences("student", Context.MODE_PRIVATE).edit()
            editor.putString("name", "yangzhiyang")
            editor.putInt("age", 18)
            editor.apply()
}

从SharedPreferences中读取数据

val prefs = getSharedPreferences("student",Context.MODE_PRIVATE)
val name = prefs.getString("name", "")
val age = prefs.getInt("age", 0)

二 SQLite数据库存储

  1. 创建数据库
  • Android为了更方便管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类可以非常简单的对数据库进行创建和升级。

SQLiteOpenHelper 是一个抽象类,想使用它需要创建一个自己的帮助类去继承它。并实现两个抽象方法:onCreate()和onUpgrade()。然后分别在这两个方法中实现创建和升级数据库的逻辑。
SQLiteOpenHelper有两个非常重要的实例方法:getReadableDatabase()和getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则要创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读的方式打开数据库,而getWritableDatabase()方法则将抛出异常。

  • 自定义数据库
class MyDatabaseHelper(val context: Context, val name: String, val 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 successed", Toast.LENGTH_SHORT).show()
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        TODO("Not yet implemented")
    }
}
  • 创建
class MainActivity : BaseActivity() {

    private lateinit var sendBtn: Button
    private lateinit var dbHelper: MyDatabaseHelper

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

    private fun setListener() {
        sendBtn.setOnClickListener {
            dbHelper.writableDatabase
        }
    }

    private fun initView() {
        sendBtn = findViewById(R.id.createDatabase)
        dbHelper = MyDatabaseHelper(this,"BookStore.db",1)
    }
}
  • 升级数据库
    假设目前已经有了BookStore.db数据库,里面有一张Book表,如果我们想再添加一张Category表用于记录图书的分类,该怎么做呢?
    在onUpgrade()方法中执行Drop语句,如果发现数据库中已经存在某张表,就删除,然后再调用onCreate()方法重新创建。
    SQLiteOpenHelper的构造函数第四个参数接收当前数据库版本号,现在只要传入比之前大的版本就能执行onUpgrage。
class MyDatabaseHelper(val context: Context, val name: String, val 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 category = "create table Category(" +
            "id integer primary key autoincrement," +
            "category_name text," +
            "category_code integer)"

    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL(createBook)
        db?.execSQL(category)
        Toast.makeText(context, "Create successed", 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)
    }
}
  • 添加数据
 insertBtn.setOnClickListener {
            val sqliteDatabase: SQLiteDatabase = dbHelper.writableDatabase
            val value1 = ContentValues().apply {
                put("name", "A")
                put("author","yzy")
                put("pages",200)
                put("price",27)
            }
            sqliteDatabase.insert("Book", null,value1)
            val value2 = ContentValues().apply {
                put("name", "A")
                put("author","lp")
                put("pages",200)
                put("price",27)
            }
            sqliteDatabase.insert("Book", null, value2)
        }
  • 更新数据
updateBtn.setOnClickListener {
            val sqLiteDatabase: SQLiteDatabase = dbHelper.writableDatabase
            val value = ContentValues().apply {
                put("price", 10)
            }
            sqLiteDatabase.update("Book",value,"name = ?", arrayOf("A"))
            sqLiteDatabase.close()
        }
  • 删除数据
deleteBtn.setOnClickListener {
            val sqLiteDatabase = dbHelper.writableDatabase
            sqLiteDatabase.delete("Book", "name = ?", arrayOf("A"))
            sqLiteDatabase.close()
        }
  • 查询数据
 queryBtn.setOnClickListener {
            val sqLiteDatabase = dbHelper.writableDatabase
            val cursor = sqLiteDatabase.query("Book", arrayOf("name","author"),"name = ? and author = ?", arrayOf("B","lp"),null,null,null)
            if (cursor.moveToFirst()){
                do {
                    //遍历cursor对象 取出数据
                    val name = cursor.getString(cursor.getColumnIndex("name"))
                    val author = cursor.getString(cursor.getColumnIndex("author"))
                    Log.e(TAG, "name-->$name")
                    Log.e(TAG,"author-->$author")
                }while (cursor.moveToNext());
            }
        }

三 使用SQL操作数据库

  • 添加数据
val insert = "insert into Book (name, author, pages, price) values(?,?,?,?)";
val sqLiteDatabase = dbHelper.writableDatabase
sqLiteDatabase.execSQL(insert, arrayOf("MyHeart", "Yan", "500", "27"))
  • 更新数据
val update = "update Book set price=? where name=?";
sqLiteDatabase.execSQL(update, arrayOf("999", "MyHeart"))
  • 删除数据
val delete = "delete from Book where name=?";
sqLiteDatabase.execSQL(delete, arrayOf("MyHeart"))
  • 查询数据
val query = "select * from Book where name = ?";
sqLiteDatabase.execSQL(query, arrayOf("MyHeart"))

四 升级数据库最佳写法

每一个数据库版本都会对应一个版本号,当指定的数据库版本号大于当前数据库版本号的时候,就会进入onUpgrade()方法中执行更新操作。

  • 下面模拟一个数据库升级
  • 第一版的程序只需要创建一张Book表
class MyDatabaseHelper(val context: Context, val name: String, val 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)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
    }
}
  • 第二版需要向数据库中再添加一张Category表

如果用户数据库的旧版本号小于等于1,就只会创建一张Category表。
当用户直接安装第二版的程序时,就会进入onCreate()方法,将两张表一起创建。
而当用户使用第二版的程序覆盖安装第一版的程序时,就会进入升级数据库的操作中,此时由于Book表已经存在了,因此只需要创建一张Category表即可。

class MyDatabaseHelper(val context: Context, val name: String, val 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 category = "create table Category(" +
            "id integer primary key autoincrement," +
            "category_name text," +
            "category_code integer)"

    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL(createBook)
        db?.execSQL(category)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        if (oldVersion <= 1){
            db?.execSQL(category)
        }
    }
}
  • 第三版需要给Book表和Category表之间建立关联,需要在Book表中添加一个category_id字段。

首先在Book表中添加了一列,这样当用户直接安装第三版程序时,这个新增列就已经自动添加成功。
然而,当用户之前已经安装了某一版本程序,现在需要覆盖安装,就会进入升级数据库的操作中。在onUpgrade()方法里,判断如果当前数据库的版本号是2,就会执行alter命令,为Book表新增一列。

class MyDatabaseHelper(val context: Context, val name: String, val 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," +
            "category_id integer)"

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

    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL(createBook)
        db?.execSQL(category)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        if (oldVersion <= 1){
            db?.execSQL(category)
        }
        if (oldVersion <= 2){
            db?.execSQL("alter table Book add column category_id integer")
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.引言   一般在做一些面试题的时候,Android有几种数据存储方案这个问题是经常碰到的。在我们实际应用中,任...
    忆念成风阅读 2,172评论 0 10
  • 持久化技术 数据持久化就是讲那些内存中的瞬时数据保存到储存设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不...
    染微言阅读 396评论 0 0
  • 前面两篇文章Android数据存储(一)和Android数据存储(二)分别使用文件存储、SharedPrefere...
    前端develop阅读 6,336评论 0 12
  • 一、文件存储 1、将文件存储到文件中 Context类中提供了一个openFileOutput(String na...
    雪脩阅读 159评论 0 0
  • 文件存储 文件存储是一种最为基本的存储方式,它的特点是不会对存储内容做出任何的修改或者格式化的操作,直接就是将数据...
    yzbkaka阅读 314评论 0 2