Android—Jetpack教程(四)

语言: CN / TW / HK

theme: smartblue

这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战

前言

在上一篇中,重点讲解了Jetpack里面的DataBinding组件。在本篇中,将会讲解Jetpack对应的Room组件。

1、Room介绍

那么何为Room?

Android采用SQLLite作为数据库存储,开源社区常见的(ORMObject Relational Mapping)库有ORMLite、GreemDAO等。Room和其他库一样,也是在SQLLite上提供了一层封装

Room重要概念

  • Entity: 实体类,对应的数据库的一张表结构,使用注解@Enity标记
  • Dao: 包含访问一系列访问数据库的方法,使用注解@Dao标记
  • Database 数据库持有者,作为与应用持久化相关数据的底层连接的主要接入点,使用注解@Database标记,另外需要满足以下条件:
    • 定义的类必须是一个继承于RoomDatabase的抽象类
    • 在注解中需要定义与数据库相关联的实体类列表,包含一个没有参数的抽象方法并且返回一个Dao对象

他们之间的关系如下图

1.png

概念说完了,现在开始实战部分!

2、开始实战

2.1 先造对应的Entity

```kotlin @Entity(tableName = "student") class Student {

@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)
var id = 0

@ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)
var name: String? = null

@ColumnInfo(name = "age", typeAffinity = ColumnInfo.INTEGER)
var age = 0

constructor(id: Int, name: String?, age: Int) {
    this.id = id
    this.name = name
    this.age = age
}

@Ignore
constructor(name: String?, age: Int) {
    this.name = name
    this.age = age
}

@Ignore
constructor(id: Int) {
    this.id = id
}

} ``` 注解解析:

  • @Entity(tableName = "student"),顾名思义,其意表明对应的表名为student
  • @PrimaryKey(autoGenerate = true),表示修饰属性为对应表主键,autoGenerate为自动增长
  • @ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT),表示为对应的列名,以及对应列名类型
  • @Ignore,表示Room组件将忽略对应构造函数,对应修饰的构造函数只能给开发者用
  • 未使用@Ignore修饰的的构造函数,将由Room组件调用(必须要留一个),当然开发者也可调用。

2.2 接着看对应的Database

满足上面所说:1、继承于RoomDatabase的抽象类;2、返回对应的Dao

```kotlin @Database(entities = [Student::class], version = 1, exportSchema = false) abstract class MyDatabase : RoomDatabase() { companion object{ private const val DATABASE_NAME = "my_db.db" private var mInstance: MyDatabase? = null

    @Synchronized
    @JvmStatic
    open fun getInstance(context: Context): MyDatabase? {
        if (mInstance == null) {
            mInstance = Room.databaseBuilder(
                context.applicationContext,
                MyDatabase::class.java,
                DATABASE_NAME
            ) //.allowMainThreadQueries() 
                .build()
        }
        return mInstance
    }
}
abstract fun getStudentDao(): StudentDao?

} `` 对应@Database(entities = [Student::class], version = 1, exportSchema = false)`注解修饰的类,表示为对应的Database

里面内容分别表示为:对应的表名(可多个)、数据库版本、暂时先理解为数据库升级需要使用的标签(后面会详解)

2.3 接下来就是对应的Dao

```kotlin @Dao interface StudentDao {

@Insert
fun insertStudent(vararg students: Student?)

@Delete
fun deleteStudent(vararg students: Student?)

@Update
fun updateStudent(vararg students: Student?)

@Query("SELECT * FROM student")
fun getAllStudent(): List<Student?>?

@Query("SELECT * FROM student WHERE id = :id")
fun getStudentById(id: Int): List<Student?>?

} ``` 这里没啥可说的,看对应注解就能知道对应作用。

不过注意的是:这里的WHERE id = :id里面的:id需要和对应方法的形参一一对应。

现在三者都准备好了,来看看如何使用!

2.4 使用Room

```kotlin class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {

private var adapter: StudentRecyclerViewAdapter? = null
private var studentDao: StudentDao? = null
private var listStudent: ArrayList<Student> = ArrayList()

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

    val recycleView = findViewById<RecyclerView>(R.id.recycleView)
    recycleView.layoutManager = LinearLayoutManager(this)

    adapter = StudentRecyclerViewAdapter(listStudent)
    recycleView.adapter = adapter

    val database: MyDatabase? = MyDatabase.getInstance(this)
    studentDao = database!!.getStudentDao()
}

fun mInsert(view: View?) {
    launch(Dispatchers.Default) {
        val s1 = Student("Jack", 22)
        val s2 = Student("Rose", 18)
        studentDao!!.insertStudent(s1, s2)
    }
}

fun mQuery(view: View?) {
    launch(Dispatchers.Default) {
        val students: ArrayList<Student> = studentDao!!.getAllStudent() as ArrayList<Student>
        withContext(Dispatchers.Main) {
            adapter!!.students = students
            adapter!!.notifyDataSetChanged()
        }
    }
}

fun mDelete(view: View?) {
    launch(Dispatchers.Default) {
        val s1 = Student(2)
        studentDao!!.deleteStudent(s1)
    }
}

fun mUpdate(view: View?) {
    launch(Dispatchers.Default) {
        val s1 = Student(3, "Jason", 21)
        studentDao!!.updateStudent(s1)
    }
}

} ``` 这里为了直观体现Room的作用,暂时使用了比较原始的方式。这样能够快速掌握Room,当掌握Room后再来玩ViewModel+LiveData+DataBinding相关的。

来看看运行效果

在这里插入图片描述 很简单的,不过这里每操作一次都需要额外去查询一次,相当的麻烦。不过在下一篇将会通过LiveData实现自动刷新数据。

Demo:点我下载