【Android】初识系列-Room,我来了~避雷指南

大家好,我是一个热爱技术的Coder。对于android,我是-【不厉害但爱‘玩’ 】。今天记录的是数据存储这块的内容。

2018年 Room 就问世了,可是到现在有多少人正式用过它呢?这个问题,我也不知道。我问出来,只是因为我之前一直没用,对于本地数据的存储涉及不到。最近项目中有需要,就记录了一下吧。以后,要多多了解新出的技术,例如最近的Compose Beta版,与时代同步。

老规矩,是什么?为什么?怎么用?三步走。

对于一个东西是什么?最好的了解方式,就是上官网,看官网的定义。上才。。不对,上链接。传送门

Room 在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库。

那为什么我们直接用 SQLite 呢?这种问题,关于为什么要用一个新的技术,而不用原来的呢?其实官网也会提上一嘴。

处理大量结构化数据的应用可极大地受益于在本地保留这些数据。最常见的用例是缓存相关数据。这样,当设备无法访问网络时,用户仍可在离线状态下浏览相应内容。设备重新连接到网络后,用户发起的所有内容更改都会同步到服务器。
由于 Room 负责为您处理这些问题,因此我们强烈建议您使用 Room(而不是 SQLite)。

在刚开始使用的时候,我发现了一些注解,那么我们先来了解一下这些注解吧。

注解名官方解释

自己理解

@Database

Marks a class as a RoomDatabase.

注意:

这需要是一抽象类并且继承RoomDatabase;

如果您的应用在单个进程中运行,在实例化 AppDatabase 对象时应遵循单例设计模式。每个 RoomDataBase 实例的成本相当高,而您几乎不需要在单个进程中访问多个实例。

就是建立数据库
@Dao

Marks the class as a Data Access Object.

注意:

被这个标注的类需要是一个接口或者是抽象类,

建议有多少个表就有多少个 Dao

就是操作数据库的(CRUD)
@Entity

Marks a class as an entity. This class will have a mapping SQLite table in the database.

注意:

至少有一个主键

可以看作-建表,数据库里的一张表

那他们之间的关系是什么呢?

那么怎么用呢?主要是三个类的创建(DatabaseDaoEntity)

不过首先要记得在gradle中配置依赖

dependencies {
  def room_version = "2.2.6"

  implementation "androidx.room:room-runtime:$room_version"
  kapt "androidx.room:room-compiler:$room_version"

  // optional - Kotlin Extensions and Coroutines support for Room
  implementation "androidx.room:room-ktx:$room_version"

  // optional - Test helpers
  testImplementation "androidx.room:room-testing:$room_version"
}

Database

@Database(entities = [RecordDataBean::class], version = 1, exportSchema = true)
abstract class RecordDatabase:RoomDatabase() {

    abstract fun chatRecordDao(): ChatRecordDao

    companion object {
        @JvmStatic
        @Volatile
        private var INSTANCE: RecordDatabase? = null

        @JvmStatic
        fun getDatabase(context: Context): RecordDatabase {
            val tempInstance = INSTANCE
            if (tempInstance != null) {
                return tempInstance
            }

            synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    RecordDatabase::class.java,
                    "record_database" //数据库名称
                ).build()
                INSTANCE = instance
                return instance
            }
        }
    }
}

这里采用了官方推荐的单例模式来创建 Database


 Dao

@Dao
interface ChatRecordDao {

    //Insert 可以返回插入数据的id值
    @Insert
    suspend fun insert(recordDataBean: RecordDataBean):Long

    @Delete
    suspend fun delete(recordDataBean: RecordDataBean): Int

    @Update
    suspend fun update(recordDataBean: RecordDataBean): Int

    @Query("select * from chat_record where user_account =:userAccount order by date asc")
    suspend fun queryAllRecord(userAccount:String): List<RecordDataBean>

    @Query("select  * from chat_record order by id desc limit 1")
    suspend fun queryLastRecord(): RecordDataBean

    @Query("select * from chat_record where msg_id = :msgId")
    suspend fun isExistInDatabase(msgId:Int): RecordDataBean?


}

根据自己的业务需求,编写操作数据库的方法。这里最关键的就是 SQL 语句的编写


Entity

@Entity(tableName = "chat_record")
data class RecordDataBean (
    @PrimaryKey(autoGenerate = true) var id:Int?=0,
    @ColumnInfo(name="user_account") var userAccount:String,
    @ColumnInfo(name="user_type") var userType:Int,
    @ColumnInfo(name="content") var content:String,
    @ColumnInfo(name="content_type") var contentType:Int,
    @ColumnInfo(name="date") var date:String,
    @ColumnInfo(name="status") var status:Int,
    @ColumnInfo(name="msg_id") var msgId:Int?=-1
)

最后就是 Entity 了。


在开发过程中,遇到一些疑问和Bug,这里分享出来,避免大家踩坑。

问题描述

Execution failed for task ':app:kaptDebugKotlin'. > A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution > java.lang.reflect.InvocationTargetException (no error message)

解决方案:因为在Dao 忘记用注解了@Dao,加上@Dao注解即可

问题描述

UNIQUE constraint failed: chat_record.id (code 1555 SQLITE_CONSTRAINT_PRIMARYKEY)

解决方案:因为主键重复了,所以报错

问题描述:如何让主键自动增加

解决方案:

data class RecordDataBean ( @PrimaryKey(autoGenerate = true) var id:Int?=0 //省略其他字段 )
//在创建一条数据的时候,将id值为空即可,这样就可以自增了 val recordDataBean3 = RecordDataBean(null)

问题追加1:我填了null,我又怎么得到插进入的数据的id是多少呢?

解决方案:在插入后,可以将对应的主键值返回

//Insert 可以返回插入数据的id值 
@Insert 
suspend fun insert(recordDataBean: RecordDataBean):Long

问题描述:如何通过动态的值来查询数据,例如通过不同userId来获取有关数据

解决方案:

@Query("select * from chat_record where user_id is (:userId) order by date asc") 
suspend fun queryAllRecord(userId: Int): List<RecordDataBean>

问题描述:如果查询结果为空,会返回什么?

测试结果:会返回空


如有疑问和指教,可评论区留言交流。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Q-CODER

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值