• Kotlin + 协程 + Room 结合使用


    文章目录

    • 前言
    • 集成Room
    • 结合协程的使用
    • 总结
    一、前言,

    现在kotlin 是趋势,那必然就要用到协程,还有就是随着jetpack 的发力,带来了很多好用的库,比如今天提到Room,是一个类似greenDao的数据库。它不但支持kotlin协程/RxJava,还具备编译期检查,是非常友好的库。我们一起来看下,在项目中怎么使用。

    二、集成Room

    1、创建一个kotlin项目,然后在app里面的build.gradle添加依赖:

    plugins {
    ...
      id 'kotlin-android-extensions'
      id 'kotlin-kapt'
    }
    dependencies {
    ...
      //room数据库
      implementation "androidx.room:room-runtime:2.4.2"
      kapt "androidx.room:room-compiler:2.4.2" // Kotlin 使用 kapt
      implementation "androidx.room:room-ktx:2.4.2"//Coroutines support for Room 协程操作库
      //lifecycle
      implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
      implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    此时,我们同步一下,开始运行项目。会报错:

    Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8
    
    • 1

    解决:将项目的jdk1.8 改成 jdk11。
    接下来还有报错:

    Can't determine type for tag '<macro name="m3_comp_assist_chip_container_shape">?attr/shapeAppearanceCornerSmall</macro>'
    
    • 1

    原因是material 的版本高了的问题。

     implementation 'com.google.android.material:material:1.8.0'
    
    • 1

    解决:我们将material,改成1.6.0。项目就能正常运行了。

    2、相关的类的创建

    2.1创建数据库的实体类
    通过在实体类上加注解@Entity,这样实体类就相当于是一张表

    import android.os.Parcelable
    import androidx.room.Entity
    import androidx.room.PrimaryKey
    import kotlinx.android.parcel.Parcelize
    
    @Parcelize
    @Entity(tableName = "Student")
    data class Student(
      @PrimaryKey
      var id: String,
      var name: String
    ) : Parcelable
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.2创建实体类的Dao:
    通过在Dao接口上加注解@Dao,就可以让dao轻松地完成增删改查。
    另外可以将 suspend Kotlin 关键字添加到 DAO 方法中,用 Kotlin 协程功能,使这些方法成为异步方法。这样可确保不会在主线程上执行这些方法。

    @Dao
    interface StudentDao {
    
      //通过@Insert 注解的onConflict 解决冲突(如果有老的数据存在则会进行替换,如果没有就插入)
      @Insert(onConflict = OnConflictStrategy.REPLACE)
      suspend fun putStudent(cacheBean: Student)
    
      @Query("select * from Student where id =:id")
      suspend fun getStudent(id: String): Student?
    
      @Query("select * from Student")
      suspend fun getAllStudent(): List<Student>?
    
      @Delete
      suspend fun delete(student: Student)
      
      @Update(onConflict = OnConflictStrategy.REPLACE)
      suspend fun update(student: Student)
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.3 创建数据库的类
    创建一个类继承RoomDatabase,加注解@Database,轻松地建数据库和建表

    import android.util.Log
    import androidx.room.Database
    import androidx.room.Room
    import androidx.room.RoomDatabase
    import androidx.sqlite.db.SupportSQLiteDatabase
    
    //后续的数据库升级通过这个version来控制,exportSchema是否导出数据库的配置信息
    @Database(entities = [Student::class], version = 2, exportSchema = false)
    abstract class StudentDatabase : RoomDatabase() {
      companion object {
        var dataBase: StudentDatabase
        val TAG = StudentDatabase::class.java.simpleName
        init {
          //如果databaseBuilder改为inMemoryDatabaseBuilder则创建一个内存数据库(进程销毁后,数据丢失)
          dataBase = Room.databaseBuilder(MyApplication.getApplicationContext(), StudentDatabase::class.java, "db_user")
            //数据库的操作是否允许在主线程中执行
            .allowMainThreadQueries()
            //数据库创建和打开后的回调,可以重写其中的方法
            .addCallback(object : Callback() {
              override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)
                Log.d(TAG, "onCreate: db_student")
              }
            })
            //数据库升级异常之后的回滚
            .fallbackToDestructiveMigration()
            .build()
        }
      }
      abstract fun getStudentDao(): StudentDao
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    2.4 创建一个MyApplication
    通过它我们来获取context。

    class MyApplication : Application() {
      init {
        instance = this
      }
      companion object {
        private var instance: MyApplication? = null
        fun getApplicationContext() : Context {
          return instance!!.applicationContext
        }
      }
      override fun onCreate() {
        super.onCreate()
      }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    三、接下来就是使用了

    通过点击按钮,进行增删改查的操作。
    增加数据:

        btn_add.setOnClickListener {
          lifecycleScope.launch {
            val studentDao = StudentDatabase.dataBase.getStudentDao()
            studentDao.putStudent(Student("101","小李"));
            studentDao.putStudent(Student("102","小王"))
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    更改数据:

        btn_update.setOnClickListener {
          lifecycleScope.launch {
            val studentDao = StudentDatabase.dataBase.getStudentDao()
            val student = studentDao.update(Student("101","小陈"))
            Log.d(TAG,student.toString());
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    删除数据:

        btn_delete.setOnClickListener {
          lifecycleScope.launch {
            val studentDao = StudentDatabase.dataBase.getStudentDao()
            val student = studentDao.delete(Student("101","小陈"))
            Log.d(TAG,student.toString());
    
            val students = studentDao.getAllStudent()
            Log.d(TAG, "students: $students")
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    查询数据:

     lifecycleScope.launch {
        btn_query.setOnClickListener {
          lifecycleScope.launch {
            val studentDao = StudentDatabase.dataBase.getStudentDao()
            val students = studentDao.getAllStudent()
            Log.d(TAG, "students: $students")
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    备注:数据库的操作一定要放到子线程中,切不可在主线程中操作,虽然可以通过allowMainThreadQueries强制开启允许这么做,但这个是测试时用,实际项目中还是不要在主线程中操作数据库,避免遇到ANR问题

    源码地址:https://github.com/shenshizhong/KotlinRoomDemo

    总结

    1 、导入依赖, 同步
    2 、创建一个实体类Student,加注解@Entity就相当于一张表
    3 、创建一个接口StudentDao,加注解@Dao就可以完成增删改查
    4 、创建抽象类继承RoomDatabase,加注解@Database,轻松地建数据库和建表
    5 、通过数据库的实例获取dao,调用方法

    如果对你有一点点帮助,那是值得高兴的事情。:)
    我的csdn:http://blog.csdn.net/shenshizhong
    我的简书:http://www.jianshu.com/u/345daf0211ad

  • 相关阅读:
    二十一、数组(1)
    树莓派+RTL-SDR 搭建APRS iGATE
    vector模拟实现
    前端面试题(JS部分)
    01-服务与服务间的通信
    go基础语法10问
    Centos7 安装部署 Kubernetes(k8s) 高可用集群
    pat乙级1120(买地攻略) C++
    UGUI学习笔记(七)自己实现圆形图片组件
    SSM - Springboot - MyBatis-Plus 全栈体系(二十六)
  • 原文地址:https://blog.csdn.net/shenshizhong/article/details/133834829