Android使用协程简单封装Room工具类
1.前言:
之前讲解过room的简单使用和升级,项目中也使用过kotlin来写room数据库,和现在项目xutils中数据库的使用相比简直不要太爽,前面两篇博客也讲解了xutils使用过程中遇到的问题和解决方案,但是发现真的是太古老了,问题太多,这次重构就想着把之前的彻底推到重来,刚好项目决定采用Kotlin开发,于是尝试了一下在room中使用协程,发现使用起来太舒服了,代码简洁,逻辑清楚,封装成RoomUtils工具类后可以直接调用,直接上代码。
2.导入room依赖
def room_version = "2.5.0"
def coroutine_version = "1.5.1"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
implementation "androidx.room:room-rxjava2:$room_version"
3.创建实体类(Entity)
/**
* @author: njb
* @date: 2023/7/15 21:46
* @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
}
4.创建数据访问对象(DAO)接口:
package com.example.roomdemo.dao
import androidx.room.*
import com.example.roomdemo.bean.User
/**
* @author: njb
* @date: 2023/7/15 21:36
* @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()
}
5.创建操作管理类UserRepository:
package com.example.roomdemo.db
import com.example.roomdemo.bean.User
import com.example.roomdemo.dao.UserDao
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
/**
* @author: njb
* @date: 2023/7/15 21:36
* @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()
}
}
}
6.封装数据库工具类RoomUtils:
package com.example.roomdemo.db
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.example.roomdemo.app.MyApp
import com.example.roomdemo.bean.User
import com.example.roomdemo.dao.UserDao
/**
* @author: njb
* @date: 2023/7/15 21:47
* @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(
MyApp.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()
}
}
7.简单使用:
class MainActivity : AppCompatActivity() {
private lateinit var roomUtils: RoomUtils
@OptIn(DelicateCoroutinesApi::class)
private fun initDataBase() {
roomUtils= RoomUtils.getInstance();
GlobalScope.launch(Dispatchers.Main) {
// 插入一条用户记录
val user = User(12,"张三","女","zhangsan@example.com")
withContext(Dispatchers.IO) {
roomUtils.insertUser(user)
Log.d("获取用户数据",user.name.toString())
}
// 更新一条用户记录
val user1 = User(12,"欧四","女","zhangsan@example.com")
withContext(Dispatchers.IO) {
roomUtils.updateUser(user1)
}
// 删除一条用户记录
withContext(Dispatchers.IO) {
roomUtils.deleteUser(user)
}
// 获取所有用户记录
val users = withContext(Dispatchers.IO) {
roomUtils.getAllUsers()
}
}
}
}
8.增删改查分开操作:
package com.example.roomdemo
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.blankj.utilcode.util.LogUtils
import com.example.roomdemo.bean.User
import com.example.roomdemo.db.RoomUtils
import kotlinx.coroutines.*
class MainActivity : AppCompatActivity() {
private lateinit var roomUtils: RoomUtils
private val tvAdd:TextView by lazy { findViewById(R.id.tv_add) }
private val tvUpdate:TextView by lazy { findViewById(R.id.tv_update) }
private val tvDelete:TextView by lazy { findViewById(R.id.tv_delete) }
private val tvQuery:TextView by lazy { findViewById(R.id.tv_query) }
private val tvDeleteUsers:TextView by lazy { findViewById(R.id.tv_delete_users) }
private val tvDeleteAll:TextView by lazy { findViewById(R.id.tv_delete_all) }
private val TAG: String = "MainLogUtils"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initDataBase()
initView()
}
private fun initDataBase() {
roomUtils = RoomUtils.getInstance();
}
@OptIn(DelicateCoroutinesApi::class)
private fun initView() {
tvAdd.setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
// 插入一条用户记录
try {
val user = User("14","张三","女","zhangsan@example.com")
withContext(Dispatchers.IO) {
roomUtils.insertUser(user)
LogUtils.d(TAG, "添加用户数据$user")
}
tvAdd.text = user.toString()
}catch (e:java.lang.Exception){
e.stackTrace
LogUtils.e(TAG,e.message.toString())
}
}
}
tvUpdate.setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
// 更新一条用户记录
val user1 = User("12","欧四","男","ousi@example.com")
withContext(Dispatchers.IO) {
roomUtils.updateUser(user1)
}
val user = roomUtils.getAllUsers()
LogUtils.d(TAG, "===更新用户数据===$user")
tvUpdate.text = user.toString()
}
}
tvQuery.setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
// 获取所有用户记录
val user = withContext(Dispatchers.IO) {
roomUtils.getAllUsers()
}
LogUtils.d(TAG, "===获取所有用户数据===$user")
tvQuery.text = user.toString()
}
}
tvDelete.setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
val user = User("12","张三","女","zhangsan@example.com")
// 删除一条用户记录
withContext(Dispatchers.IO) {
roomUtils.deleteUser(user)
LogUtils.d(TAG, "===删除用户数据===$user")
}
val user1 = roomUtils.getAllUsers()
tvDelete.text = user1.toString()
}
}
tvDeleteUsers.setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
val user = roomUtils.getAllUsers()
val user1 : List<User>
// 删除所有用户
withContext(Dispatchers.IO) {
roomUtils.deleteUsers(user)
user1 = roomUtils.getAllUsers()
LogUtils.d(TAG, "===删除多个用户数据===$user1")
}
tvDeleteUsers.text = user1.toString()
}
}
tvDeleteAll.setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
val user : List<User>
// 删除所有用户
withContext(Dispatchers.IO) {
roomUtils.deleteAllUser()
user = roomUtils.getAllUsers()
LogUtils.d(TAG, "===删除所有用户数据===$user")
}
tvDeleteAll.text = user.toString()
}
}
}
}
9.布局代码:
<?xml version="1.0" encoding="utf-8"?>
<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="0dp"
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="0dp"
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="0dp"
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="0dp"
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="0dp"
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="0dp"
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>
10.遇到问题:
10.1 运行时报错提示版本有问题:
解决方法:把Room版本升级到最新的2.5.0,当然2.4.0也是没问题的,由于我的插件版本是7.4.2,项目的目标版本是33,
所以我为了统一,把room版本也升级成最新的了.
10.2 生成数据库时一直报错:
刚开始以为是方法添加协程导致的,去掉后发现没有用,查找各种资料最后回看以前的项目才发现问题所在,真是好久没用新的组件,基本的配置都忘记了,真是粗心大意啊~~重要的事情说三遍:
一定要记得配置room的文件生成路径!!
一定要记得配置room的文件生成路径!!
一定要记得配置room的文件生成路径!!
//指定room.schemaLocation生成的文件路径
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
10.3 添加数据时不可添加重复的id:
这里是指id作为主键和key,实际项目中数据都是从后台获取的,id不会重复,先看错误的写法:
/**
* @author: njb
* @date: 2023/7/15 21:46
* @desc:
*/
@Entity(tableName = "User")
data class User(
@PrimaryKey val id: Int,
@ColumnInfo(name = "name") var name: String?,
@ColumnInfo(name = "sex") var sex: String?,
@ColumnInfo(name = "email") var email: String?,
)
正确的写法:id作为主键,而且是自增的,正常项目很少遇到此问题,这里只是测试demo.
/**
* @author: njb
* @date: 2023/7/15 21:46
* @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.增删改查日志打印:
12.实现的效果如下:
13.文章总结:
以上就是今天的使用协程操作数据库简单使用和封装,遇到了几个简单的问题,但是最后找到原因都解决了,而且发现使用协程后封装了roomUilts非常简单,操作起来也方便,增删改查各种操作都极其简单,大家如果感兴趣的可以去尝试下,大胆干快点散,要勇于尝试新技术,新的东西写起来很有意思,让人瞬间头脑清醒,路漫漫其修远兮,吾将上下而求索!!
14.项目源码:
https://gitee.com/jackning_admin/room-utils-demo