前言
在上一篇中,重点讲解了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对象
他们之间的关系如下图
概念说完了,现在开始实战部分!
2、开始实战
2.1 先造对应的Entity
@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
@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
@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
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:点我下载