Android存储

1. SharedPreferences

1.1 定义

  • SharedPreferences是一种轻量级的数据存储方式,采用Key/Value的方式进行映射,以键值对的形式存储在XML中
  • 千万不要使用SharedPreferences去存储大量的数据,否则会严重影响应用的性能,甚至出现ANR

1.2 具体使用

1.2.1 保存数据

  • 本质: 以键值对的形式存储在xml文件中
  • 文件存储在/data/data/shared_prefs目录下
  • 获取SharedPreferences对象的方法:
         1.Context类中的getSharedPreferences()方法
         2.Activity类中的getPreferences()方法
  • 使用步骤:
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)



        val editor = getSharedPreferences("data",Context.MODE_PRIVATE).edit()

        // 步骤1:
        // 参数1:指定该文件的名称,名称不用带后缀,后缀会由Android自动加上
        // 参数2:指定文件的操作模式,共有4种操作模式,分别是:
        // Context.MODE_PRIVATE = 0:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容
        // Context.MODE_APPEND = 32768:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。 (已废弃)
        // Context.MODE_WORLD_READABLE = 1:表示当前文件可以被其他应用读取 (已废弃)
        // Context.MODE_WORLD_WRITEABLE = 2:表示当前文件可以被其他应用写入 (已废弃)


        // 步骤2:通过edit()方法获取编辑器对象



        // 步骤3: 以键值对的方式写入数据
        editor.putString("name","Tom")
        editor.putInt("age",28)
        editor.putBoolean("married",false)
        
        // 步骤4: 提交修改
        editor.apply()
    }

1.2.2 读取数据

  • 使用步骤:
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)



        val prefs = getSharedPreferences("data",Context.MODE_PRIVATE)
        // 步骤1:
        // 参数1:指定该文件的名称,名称不用带后缀,后缀会由Android自动加上
        // 参数2:指定文件的操作模式,共有4种操作模式,分别是:
        // Context.MODE_PRIVATE = 0:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容
        // Context.MODE_APPEND = 32768:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。 (已废弃)
        // Context.MODE_WORLD_READABLE = 1:表示当前文件可以被其他应用读取 (已废弃)
        // Context.MODE_WORLD_WRITEABLE = 2:表示当前文件可以被其他应用写入 (已废弃)


        val name = prefs.getString("name","")
        val age = prefs.getInt("age",0)
        val married = prefs.getBoolean("married",false)


        // 步骤2:
        // getxxx()
        // 参数1: 要获取的key
        // 参数2 : 默认值(即如果不存在该key时的返回值)

    }

2. SQLite

2.1 定义

  • SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源少,不仅支持标准的SQL语法,还遵循了数据库的ACID特性
  • 正式由于上述的优点,所以Android选择直接将该数据库嵌入到了系统当中

2.2 SQLiteOpenHelper

2.2.1 要点

  • 为了让我们能够更加方便地管理数据库,所以专门提供了一个SQLiteOpenHelper帮助类,借助这个类可以非常简单地对数据库进行创建和升级
  • SQLiteOpenHelper是一个抽象类,有两个抽象方法:onCreate(),onUpgrade(),我们必须自己去重写这两个方法
  • 两个重要的实例方法:getReadableDatabase(),getWritableDatabase()。这两个方法都可以打开一个现有的数据库(不存在则直接创建)并返回一个可对数据库进行读写操作的对象。但是当数据库不可写入的时候,getReadableDatabase()方法将以可读方式打开,而getWritableDatabase()则会抛出异常

2.2.2 创建表

class MyDatabaseHelper(val context: Context,name: String,version: Int) : SQLiteOpenHelper(context,name,null,version){

   // integer:整型  real:浮点型   text:文本类型  blob:二进制类型
   
   private var 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) {

   }
}

2.2.3 升级数据库

  • 如果数据库已经创建好了,这个时候要再新建一张表或者修改表的结构,在onCreate()方法里执行db.exec()是没有变化的,因为onCreate()不会再执行一次。
  • 解决方案可以通过卸载程序然后重新执行onCreate(),但是这种方法太极端,所以正确的做法是onUpgrade()
  • 比如新增一张表Category:
class MyDatabaseHelper(val context: Context,name: String,version: Int) : SQLiteOpenHelper(context,name,null,version){

    // integer:整型  real:浮点型   text:文本类型  blob:二进制类型

    private var createBook = "create table Book ("+
            "id integer primary key autoincrement," +
            "author text," +
            "price real," +
            "pages integer," +
            "name text)"
    
    private var 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)

    }

    
    // 在onUpgrade()方法中执行两条drop语句,如果发现数据库中已经存在表就删除,然后调用onCreate()重新创建
    // 怎么让onUpgrade()执行,就是version参数,它表示数据库的版本号,只要现在的版本号大于之前版本号,就会执行该方法
    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)
    }
}

2.2.4 添加数据

  • SQLiteDatabase中提供了一个insert()方法,专门用于添加数据。它接收3个参数:
         1.表名(希望向哪张表添加数据)
         2.用于在未指定添加数据的情况下给某些可能为空的列自动赋值NULL,一般不会使用,直接传入null即可
         3.一个ContentValues对象,提供了一系列的put()方法重载,用于向ContentValues中添加数据

  • 代码如下:

override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main2)
       
       val dbHelper = MyDatabaseHelper(this,"BookStore.db",2)
       
       val db = dbHelper.writableDatabase
       
       val values = ContentValues().apply { 
           put("name","David")
           put("author","Dan Brown")
           put("pages",454)
           put("price",16.69)
       }
       
       
       db.insert("Book",null,values)

   }

2.2.5 更新数据

  • SQLiteDatabase提供了update()方法用于对数据进行更新,该方法接收4个参数:
        1.表名
        2.ContentValues对象,要把更新数据组装进去
        3,4.这两个参数共同用来约束更新某一行或某几行中的数据,不指定的话默认更新所有行
  • 代码如下:
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)

        // 1. 获取到SQLiteDatabase对象来对数据库进行操作
       var dbHelper = MyDatabaseHelper(this,"Book_store.db",1)

        // 2.通过SQLiteDatabase的getWritableDatabase获得可以向数据库进行读写操作的对象db
        val db = dbHelper.writableDatabase
        
        // 3.得到一个ContentValues对象用来组装数据
        val values = ContentValues()
        values.put("price",10.09)
        
        // 4.arrayOf()方法是Kotlin提供的一种用于便捷创建数组的内置方法
        db.update("Book",values,"name=?", arrayOf("David"))

    }

2.2.6 删除数据

  • 几乎和更新数据一样,这里就不再赘述了

2.2.7 查询数据

  • CRUD中最难的操作,提供了一个query()方法,该方法接收7个参数:
        1.表名
        2.指定去查询哪几列,默认所有列
        3,4.用于约束查询一行或者某几行的数据,不指定则默认所有行
        5.指定需要group by的列
        6.对group by之后的数据进行进一步过滤
        7.指定查询结果的排序方式

  • 代码如下:

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

        // 1. 获取到SQLiteDatabase对象来对数据库进行操作
       var dbHelper = MyDatabaseHelper(this,"Book_store.db",1)

        // 2. 通过SQLiteDatabase的getWritableDatabase获得可以向数据库进行读写操作的对象db
        val db = dbHelper.writableDatabase

        // 3. 查询Book的所有数据
        val cursor = db.query("Book",null,null,null,null,null,null)
        
        //4. 遍历Cursor对象,取出数据
        if (cursor.moveToFirst()) {
            do {
                val name = cursor.getString(cursor.getColumnIndex("name"))
                val author = cursor.getString(cursor.getColumnIndex("author"))
                val pages = cursor.getInt(cursor.getColumnIndex("pages"))
            }while (cursor.moveToNext())
        }
        cursor.close()

    }

2.3 使用sql语句操作数据库

// 使用SQL的增删改查
        db.execSQL("insert into Book(name,author,pages,price) values(?,?,?,?)", arrayOf("David","Dan Brown","454","16.96"))
        
        db.execSQL("update Book set price = ? where name = ?", arrayOf("10.99","David"))
        
        db.execSQL("delete from Book where pages > ?", arrayOf("500"))
        
        val query = db.rawQuery("select * from Book",null)

3. 文件存储

3.1 定义

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

3.2 将数据存储到文件中

3.2.1 openFileOutput()

  • 该方法用于将数据存储到指定的文件中,该方法有两个参数:
        1.文件名,在文件创建的时候使用
        2.文件的操作模式,主要有MODE_PRIVATE和MODE_APPEND
  • 该方法返回的是一个FileOutPutStream对象,得到该对象后就可以使用Java流将数据写入文件中了
  • 代码如下:
// 首先得到一个FileOutputStream对象,得到这个对象后就可以将数据写入文件中了
   // use函数是Kotlin提供的一个内置扩展函数,它会保证在Lambda表达式中的代码全部执行完成后自动关闭外层的流
   // 这样就不需要手动去关闭流了
   private fun save(inputText:String) {
       try {
           val output = openFileOutput("data",Context.MODE_PRIVATE)
           val write = BufferedWriter(OutputStreamWriter(output))
           write.use {
               it.write(inputText)
           }
       }catch (e : IOException) {
           e.printStackTrace()
       }
   }

3.3 从文件中读取数据

3.3.1 openFileInput()

  • 该方法只接收一个参数,即要读取的文件名
  • 代码如下:
// 首先通过openFileInput()获取了一个FileInputStream对象,然后通过它构建出了一个InputStreamReader对象
   // 再通过InputStreamReader构建出了BufferedReader对象
   // forEachLine函数是Kotlin的一个内置扩展函数,会将读取到的每行内容都回调到Lambda表达式中
   private 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学习笔记)