前期工作:
首先添加依赖:
//room数据库
def roomVersion = "2.3.0"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
// To use Kotlin annotation processing tool (kapt) 添加这个,编译的时候系统会帮我们自动生成代码
kapt("androidx.room:room-compiler:$roomVersion")
// optional - Kotlin Extensions and Coroutines support for Room
implementation("androidx.room:room-ktx:$roomVersion")
?还需要声明:
defaultConfig {
applicationId "com.xxx.xxxxxxxxxx"
...
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
apply plugin: 'kotlin-kapt'
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
?
代码实现
1、创建实体对象,一个实体就是一张表(每次修改这个实体的时候数据表都会发生变化):
@Entity(tableName = "table_student")//不声明tableName就会以类名为表明
data class Student(
@PrimaryKey(autoGenerate = true)//唯一key,自动增加
var id: Int = 0,
@ColumnInfo(name = "student_name")//不声明name则以字段名为列表名
var name: String? = "",
@ColumnInfo(name = "student_age")
var age: Int? = 0
) {
constructor(name: String, age: Int) : this() {
this.name = name
this.age = age
}
}
2、创建抽象Dao,编译的时候系统会帮我们自动生成代码:
加suspend关键字是因为这些接口都需要在子线程里面操作,这里用协程
@Dao
interface StudentDao {
@Insert
suspend fun insertStudent(student: Student)
@Update
suspend fun updateStudent(student: Student)
@Delete
suspend fun deleteStudent(student: Student)
@Query("select * from table_student where id = :id")
suspend fun getStudent(id:Int):Student?
@Query("select * from table_student where student_name like :name")
suspend fun getStudents(name:String):List<Student>
@Query("select * from table_student")
suspend fun getAllStudents():List<Student>
}
3、创建数据库抽象类,编译的时候系统会帮我们自动生成代码:
@Database(entities = [Student::class],version = 1)//每次实体做了修改这个version就要升级,会触发数据库迁移的操作
abstract class MyDb constructor():RoomDatabase(){
abstract fun getStudentDao():StudentDao
}
4、数据库抽象类的实现只要生成一次,用一个单例来管理:
class MyDateBaseHelper(context: Context) {
private val build:MyDb = Room
.databaseBuilder(context, MyDb::class.java, "my_db_test")
.fallbackToDestructiveMigration()//破坏式迁移数据库(第三步那个version改变的时候触发。这里仅做测试,实际开发需要做数据库的迁移)
// .allowMainThreadQueries()//允许主线程中操作。默认不允许,如果直接在主线程中操作会崩溃。我们这里用了协程,所以不需要声明这个,实际开发中也保证不要在主线程做这种耗时操作
.build()
companion object {
@Volatile
private var instance: MyDateBaseHelper? = null
fun getInstance(context: Context): MyDateBaseHelper? {
if (instance == null) {
synchronized(MyDateBaseHelper::class.java) {
if (instance == null) {
instance = MyDateBaseHelper(context)
}
}
}
return instance
}
}
fun getStudentDao():StudentDao{
return build.getStudentDao()
}
}
5、在activity中使用:
//插入、删除、修改三个按钮的点击事件,查询在删除和修改里面有体现
private fun btnClick(view: View) {
when (view.id){
R.id.btnInsert -> {
//插入一个学生对象
if(edit.text.isEmpty()){
Toast.makeText(this,"no input",Toast.LENGTH_SHORT).show()
return
}
GlobalScope.launch(Dispatchers.Main){
withContext(Dispatchers.IO){
studentDao.insertStudent(Student(edit.text.toString(),20))
}
updateList()
}
}
R.id.btnDelete ->{
//删除id为输入框中值的学生(这里仅作简单测试,没做try-catch,实际开发这个id值确保是数字)
GlobalScope.launch(Dispatchers.Main){
val student = getStudent(edit.text.toString().toInt()))//先获取这个学生,再做删除操作
if(student == null){
Toast.makeText(this@RoomTestActivity,"student == null",Toast.LENGTH_SHORT).show()
return@launch
}
studentDao.deleteStudent(student)
updateList()
}
}
R.id.btnUpdate ->{
//更新,把id为输入框中值的那个对象修改名字和年龄
GlobalScope.launch(Dispatchers.Main){
val student = getStudent(seekBar.progress)
if(student == null){
Toast.makeText(this@RoomTestActivity,"student == null",Toast.LENGTH_SHORT).show()
return@launch
}
student.age = 25
student.name = "updateTest"
studentDao.updateStudent(student)
updateList()
}
}
}
}
/**
* 根据id获取学生
*/
private suspend fun getStudent(id:Int):Student?{
return withContext(Dispatchers.IO){
studentDao.getStudent(id)
}
}
/**
* 更新UI上的列表
*/
private suspend fun updateList(){
val list = withContext(Dispatchers.IO){
studentDao.getAllStudents()
}
adapter.submitList(list)
}
就可以了。本人是kotlin新手,如果代码有什么错误或者需要优化的地方麻烦评论探讨。
最后给上demo地址:KotlinStudy: 个人学习demo。只会java的我用kotlin语言边学边写。目前做了个room数据库增删改查的demo,持续更新https://gitee.com/xaehu/KotlinStudy?
|