Android在KSP中简单使用Room

发布于:2025-03-31 ⋅ 阅读:(42) ⋅ 点赞:(0)

Android在KSP中简单使用Room

最近下载了最新版Studio,好多依赖和配置都需要升级,之前使用过room封装数据库工具类,最近在整理ksp相关,于是把room也升级了,简单记录一下升级过程,直接上代码。

1.添加KSP依赖配置:

#KSP
ksp = "2.1.10-1.0.29"

ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }

在这里插入图片描述

2.项目的依赖配置:

plugins {
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.android.library).apply(false)
    alias(libs.plugins.kotlin.android) apply false
    alias(libs.plugins.ksp).apply(false)
}

在这里插入图片描述

3.app的build.gradle配置:

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.ksp)
}

在这里插入图片描述

4.添加room配置:

#Room
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
util-codex = { group = "com.blankj", name= "utilcodex", version.ref = "utilcodex" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }
[bundles]
room = [
    "androidx-room-ktx",
    "androidx-room-runtime",
]

在这里插入图片描述

在这里插入图片描述

5.在build.gradle添加room:

api(libs.bundles.room)
ksp(libs.androidx.room.compiler)

在这里插入图片描述

6.room数据库生成文件路径:

6.1 路径配置:

ksp {
    arg("room.schemaLocation", "$projectDir/schemas")
}
    defaultConfig {
        applicationId = "com.example.ksproomdemo"
        minSdk = 24
        targetSdk = 36
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        ksp {
            arg("room.schemaLocation", "$projectDir/schemas")
        }
    }

在这里插入图片描述

6.2. room对应的jvm版本:

compileOptions {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
    jvmTarget = "17"
}
ksp {
    arg("jvmTarget", "17")
}

6.3 生成的数据库文件如下:

{
  "formatVersion": 1,
  "database": {
    "version": 1,
    "identityHash": "1599160ffa834f06d3bdbe0680959e41",
    "entities": [
      {
        "tableName": "User",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` TEXT NOT NULL, `name` TEXT NOT NULL, `sex` TEXT NOT NULL, `email` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)",
        "fields": [
          {
            "fieldPath": "userId",
            "columnName": "userId",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "sex",
            "columnName": "sex",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "email",
            "columnName": "email",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "views": [],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1599160ffa834f06d3bdbe0680959e41')"
    ]
  }
}

在这里插入图片描述

7.布局文件:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_add"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:text="添加数据"
        android:textColor="@color/white"
        android:textSize="18sp"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:background="@color/design_default_color_primary"/>

    <TextView
        android:id="@+id/tv_update"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:text="修改数据"
        android:textColor="@color/white"
        android:textSize="18sp"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_add"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:background="@color/design_default_color_primary"/>

    <TextView
        android:id="@+id/tv_query"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:text="查询数据"
        android:textColor="@color/white"
        android:textSize="18sp"
        android:gravity="center"
        android:singleLine="true"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_update"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:background="@color/design_default_color_primary"/>
    <TextView
        android:id="@+id/tv_delete"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:text="删除数据"
        android:textColor="@color/white"
        android:textSize="18sp"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_query"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:background="@color/design_default_color_primary"/>
    <TextView
        android:id="@+id/tv_delete_users"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:text="删除多个数据"
        android:textColor="@color/white"
        android:textSize="18sp"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_delete"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:background="@color/design_default_color_primary"/>

    <TextView
        android:id="@+id/tv_delete_all"
        android:layout_width="200dp"
        android:layout_height="40dp"
        android:text="删除所有数据"
        android:textColor="@color/white"
        android:textSize="18sp"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_delete_users"
        android:layout_marginTop="20dp"
        android:layout_marginStart="20dp"
        android:layout_marginEnd="20dp"
        android:background="@color/design_default_color_primary"/>

</androidx.constraintlayout.widget.ConstraintLayout>

8.数据库工具类RoomUtils:

package com.example.db

import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.example.app.RoomApp
import com.example.ksproomdemo.bean.User
import com.example.ksproomdemo.dao.UserDao

/**
 * @author: njb
 * @date:   2025/3/30 1:25
 * @desc:   描述
 */
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}
class RoomUtils private constructor(){
    private val database: AppDatabase by lazy {
        Room.databaseBuilder(
            RoomApp.instance.applicationContext,
            AppDatabase::class.java, "app-database"
        ).build()
    }

    companion object {
        @Volatile
        private var instance: RoomUtils? = null

        fun getInstance(): RoomUtils {
            return instance ?: synchronized(this) {
                instance ?: RoomUtils().also { instance = it }
            }
        }
    }

    private val userRepository: UserRepository by lazy {
        UserRepository(database.userDao())
    }

    suspend fun insertUser(user: User) {
        userRepository.insertUser(user)
    }

    suspend fun updateUser(user: User) {
        userRepository.updateUser(user)
    }

    suspend fun deleteUser(user: User) {
        userRepository.deleteUser(user)
    }

    suspend fun getAllUsers(): List<User> {
        return userRepository.getAllUsers()
    }

    suspend fun deleteUsers(user: List<User>) {
        return userRepository.deleteUsers(user)
    }


    suspend fun deleteAllUser() {
        userRepository.deleteAllUser()
    }
}

9.UserRepository:

package com.example.db

import com.example.ksproomdemo.bean.User
import com.example.ksproomdemo.dao.UserDao
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

/**
 * @author: njb
 * @date:   2025/3/30 1:26
 * @desc:   描述
 */
class UserRepository (private val userDao: UserDao){
    suspend fun insertUser(user: User) {
        withContext(Dispatchers.IO) {
            userDao.insertAll(user)
        }
    }

    suspend fun updateUser(user: User) {
        withContext(Dispatchers.IO) {
            userDao.updateUser(user)
        }
    }

    suspend fun deleteUser(user: User) {
        withContext(Dispatchers.IO) {
            userDao.delete(user)
        }
    }

    suspend fun getAllUsers(): List<User> {
        return withContext(Dispatchers.IO) {
            userDao.getAll()
        }
    }

    suspend fun deleteUsers(user: List<User>) {
        withContext(Dispatchers.IO) {
            userDao.deleteUsers(user)
        }
    }

    suspend fun deleteAllUser() {
        withContext(Dispatchers.IO) {
            userDao.deleteAllUserInfo()
        }
    }
}

10.Dao和实体类:

package com.example.ksproomdemo.dao

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import com.example.ksproomdemo.bean.User

/**
 * @author: njb
 * @date:   2025/3/30 1:06
 * @desc:   描述
 */
@Dao
interface UserDao {
    @Query("SELECT * FROM user")
    suspend fun getAll(): List<User>

    @Query("SELECT * FROM user WHERE id IN (:userIds)")
    suspend fun loadAllByIds(userIds: IntArray): List<User>

    @Query("SELECT * FROM user WHERE name LIKE :name")
    suspend fun findByName(name: String): User?

    @Query("SELECT *FROM user WHERE id LIKE:userId")
    suspend fun findById(userId: Int): User?

    @Update
    suspend fun updateUser(user: User)

    @Insert
    suspend fun insertAll(users: User)

    @Delete
    suspend fun delete(user: User)

    @Delete
    suspend fun deleteUsers(user: List<User>)

    @Query("DELETE FROM User")
    suspend fun deleteAllUserInfo()
}
package com.example.ksproomdemo.bean

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

/**
 * @author: njb
 * @date:   2025/3/30 1:24
 * @desc:   描述
 */
@Entity(tableName = "User")
data class User(
    var userId: String = "",
    @ColumnInfo(name = "name") var name: String = "",
    @ColumnInfo(name = "sex") var sex: String = "",
    @ColumnInfo(name = "email") var email: String = "",
){
    @PrimaryKey(autoGenerate = true)
    var id: Long = 0
}

11.测试代码:

package com.example.ksproomdemo

import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.SnackbarUtils
import com.blankj.utilcode.util.ToastUtils
import com.example.db.RoomUtils
import com.example.ksproomdemo.bean.User
import com.example.ksproomdemo.databinding.ActivityMainBinding
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class MainActivity : AppCompatActivity() {
    private lateinit var roomUtils: RoomUtils
    private lateinit var binding:ActivityMainBinding
    private val TAG = "Mainivity"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        initView()
        initListener()
    }

    private fun initView() {
        roomUtils = RoomUtils.getInstance()
    }

    private fun initListener() {
        binding.tvAdd.setOnClickListener {
            lifecycleScope.launch {
                val user = User("18","张三","男","zhangsan@qq.com")
                withContext(Dispatchers.IO) {
                    roomUtils.insertUser(user)
                    LogUtils.d(TAG, "----添加用户数据----$user")
                }
                Snackbar.make(binding.tvAdd,user.toString(),Snackbar.LENGTH_LONG).show()
            }
        }
        binding.tvUpdate.setOnClickListener {
            lifecycleScope.launch {
                val user = User("12","Tom","女","ousi@example.com")
                withContext(Dispatchers.IO){
                    roomUtils.updateUser(user)
                    LogUtils.d(TAG, "----更新用户数据----$user")
                }
                Snackbar.make(binding.tvUpdate,user.toString(),Snackbar.LENGTH_LONG).show()
            }
        }
        binding.tvQuery.setOnClickListener {
            lifecycleScope.launch {
                val user = withContext(Dispatchers.IO){
                    RoomUtils.getInstance().getAllUsers()
                }
                LogUtils.d(TAG, "----查询用户数据----$user")
                Snackbar.make(binding.tvQuery,user.toString(),Snackbar.LENGTH_LONG).show()
            }
        }
        binding.tvDelete.setOnClickListener {
            lifecycleScope.launch {
                val user = User("18","张三","男","zhangsan@qq.com")
                withContext(Dispatchers.IO){
                    RoomUtils.getInstance().deleteUser(user)
                }
                LogUtils.d(TAG, "----删除一条用户数据----$user")
                Snackbar.make(binding.tvDelete,user.toString(),Snackbar.LENGTH_LONG).show()
            }
        }
        binding.tvDeleteUsers.setOnClickListener {
            lifecycleScope.launch {
                val user = roomUtils.getAllUsers()
                val user1 : List<User>
                // 删除所有用户
                withContext(Dispatchers.IO) {
                    roomUtils.deleteUsers(user)
                    user1 = roomUtils.getAllUsers()
                }
                LogUtils.d(TAG, "===删除多个用户数据===$user1")
                Snackbar.make(binding.tvDelete,user1.toString(),Snackbar.LENGTH_LONG).show()
            }
        }
        binding.tvDeleteAll.setOnClickListener {
            lifecycleScope.launch {
                val user : List<User>
                // 删除所有用户
                withContext(Dispatchers.IO) {
                    roomUtils.deleteAllUser()
                    user = roomUtils.getAllUsers()
                }
                LogUtils.d(TAG, "===删除所有用户数据===$user")
                Snackbar.make(binding.tvDelete,user.toString(),Snackbar.LENGTH_LONG).show()
            }
        }
    }
}

12.日志打印:

2025-03-30 22:53:13.383  3712-3760  Mainivity               com.example.ksproomdemo              D  ----添加用户数据----User(userId=18, name=张三, sex=, email=zhangsan@qq.com)

2025-03-30 22:53:26.322  3712-3760  Mainivity               com.example.ksproomdemo              D  ----更新用户数据----User(userId=12, name=Tom, sex=, email=ousi@example.com)

2025-03-30 22:53:37.349  3712-3712  Mainivity               com.example.ksproomdemo              D  ----查询用户数据----[User(userId=18, name=张三, sex=, email=zhangsan@qq.com), User(userId=18, name=张三, sex=, email=zhangsan@qq.com), User(userId=18, name=张三, sex=, email=zhangsan@qq.com)]

2025-03-30 22:53:49.061  3712-3712  Mainivity               com.example.ksproomdemo              D  ----删除一条用户数据----User(userId=18, name=张三, sex=, email=zhangsan@qq.com)

2025-03-30 22:53:58.775  3712-3712  Mainivity               com.example.ksproomdemo              D  ===删除多个用户数据===[]
  Mainivity               com.example.ksproomdemo              D  ===删除所有用户数据===[]

13.实现效果如下:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

14.总结:

  • ksp要添加相应插件和依赖,配置方式有所改变.
  • ksp中room的路径要配置正确.
  • ksp中jvm版本要对应.
  • 升级到最新的gradle后compileSdk版本要使用最新的.

15.项目源码:

https://gitee.com/jackning_admin/ksproom-demo


网站公告

今日签到

点亮在社区的每一天
去签到