Android使用协程简单封装Room工具类

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android 开发中,数据库操作是非常常见的任务。为了方便复用和维护,我们可以将数据库操作封装成一个工具类。以下是一个简单数据库工具类封装示例: ```java public class DatabaseHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "my_database.db"; private static final int DATABASE_VERSION = 1; private static DatabaseHelper instance; private SQLiteDatabase database; private DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } public synchronized static DatabaseHelper getInstance(Context context) { if (instance == null) { instance = new DatabaseHelper(context.getApplicationContext()); } return instance; } public synchronized SQLiteDatabase open() { if (database == null || !database.isOpen()) { database = instance.getWritableDatabase(); } return database; } public synchronized void close() { if (database != null) { database.close(); database = null; } } @Override public void onCreate(SQLiteDatabase db) { // 创建数据库表 db.execSQL("CREATE TABLE my_table (_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 数据库升级操作 } } ``` 这个工具类继承自 `SQLiteOpenHelper` 类,重写了 `onCreate` 和 `onUpgrade` 方法,用于创建和升级数据库表。同时,这个工具类使用了单例模式和同步锁来保证数据库的安全性和线程安全性。 使用时,可以通过 `getInstance` 方法获取数据库实例,然后调用 `open` 方法打开数据库,进行相关的增删改查操作。最后要记得调用 `close` 方法关闭数据库连接,释放资源。 ```java DatabaseHelper dbHelper = DatabaseHelper.getInstance(context); SQLiteDatabase db = dbHelper.open(); // 执行增删改查操作 dbHelper.close(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值