Android Jetpack(五):ROOM

目录

  1. ROOM是什么
  2. 为什么出现呢?
  3. 如何使用呢?
  4. 项目中如何使用呢?
  5. 数据库迁移

一、ROOM是什么

Jetpack中的一门技术,Room 是 Google 推出的一个在 SQLite 上提供抽象层的持久存储库。使用ROOM我们可以快速的生成数据库,表,可以快速的去访问。
涉及到的知识点:Entity,Dao,Database,Migration,Repository。

**Entity:**这是一个Model类,对应于数据库中的一张表。Entity类是Sqlite表结构在Java类的映射。

**Dao:**数据访问对象,我们可以通过它来增删改查,每一张表对应一个Dao。

Database:

Migration:

Repository:

二、为什么出现呢?

流畅地访问 SQLite 数据库。

三、如何使用呢?

1.增加插件:由于 Room框架中使用了注解处理器,因此需要使用 kapt 依赖,需要在 build.gradle 文件中引入 kapt 插件。

id 'kotlin-kapt'

2.引入依赖

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.jetbrains.kotlin.android)
    id("kotlin-kapt")
}

dependencies {
	 implementation "androidx.room:room-runtime:2.3.0"
	 kapt "androidx.room:room-compiler:2.3.0"
 }

3.创建一个关于用户的Entity,即创建一张用户表。

(1)Entity

@Entity(tableName = "user")
data class UserEntity(
    @PrimaryKey(autoGenerate = true)
    var id: Int?,
    @ColumnInfo
    var account:String,
    @ColumnInfo
    var nickname:String
)
如果不想传递id?

(2)Dao

@Dao
interface UserDao {
    @Query("select * from user")
    fun getAll():List<UserEntity>

    @Insert
    fun insertUser(userEntity: UserEntity)

    @Query("select * from user where account=:account")
    fun getInfoByAct(account:String):List<UserEntity>
}

(3)DataBase:为什么要搞抽象的呢?【因为我们只是定义信息,实例化是由ROOM来实现的。】
这是一个数据库,需要协助数据库的版本号,有哪些数据表.

注意,数据库对象不推荐一直创建的,消耗资源,所以我们需要做成单例的。

@Database(
    entities = [UserEntity::class],
    version = 1
)
abstract class MyDataBase:RoomDatabase() {

    companion object{
        private var instance:MyDataBase?=null //可空类型 在Kotlin中,默认情况下,所有基本数据类型(如 Int, Double 等)都是非空的

        fun getInstance(context:Context):MyDataBase{
            if (instance==null) {
                 Room.inMemoryDatabaseBuilder(context,MyDataBase::class.java)
                    .build()
                    .apply {
                        instance = this
                    }

            }
            //当你有一个可空类型的变量,但在某个上下文中你知道它绝对不会是 null,你可以使用 !! 来告诉Kotlin编译器这个变量是非空的,并直接解引用它。但是,如果变量实际上是 null,使用 !! 会导致运行时异常
            return instance!!//非空断言 如果条件判断失败(即 instance 没有被成功初始化),这里就会抛出 NullPointerException。
        }


    }

    abstract fun getUserDao():UserDao
}

(4) 使用:数据库的插入和查询,我开启了协程,因为都是耗时操作。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
        val userDao = MyDataBase.getInstance(this).getUserDao()
        var button : Button = findViewById(R.id.button)
        var text: TextView = findViewById(R.id.textView)
        button.setOnClickListener{
            lifecycleScope.launch (Dispatchers.IO) {
                val all = userDao.getAll()
                lifecycleScope.launch(Dispatchers.Main) {
                    text.text= all.toString()

                }

            }


        }
        var button2 : Button = findViewById(R.id.button2)
        button2.setOnClickListener{
            lifecycleScope.launch (Dispatchers.IO){
                userDao.insertUser(UserEntity(0,"account1","昵称"))

            }
        }

    }
}

如果你不想传递id,可以这样,指定参数去赋值。
 lifecycleScope.launch (Dispatchers.IO){
                userDao.insertUser(UserEntity(
                    account = "account1", nickname = "昵称"
                ))

            }

3.1 生成文件

上述的数据库,其实都是生成在内存当中,如果程序重启数据就会丢失。如果想存储到文件里面,我们需要将inMemoryDatabaseBuilder方法换成databaseBuilder方法,这个方法,需要提供一个数据库名

Room.databaseBuilder(context,MyDataBase::class.java,"UserDb")
                    .build()
                    .apply {
                        instance = this
                    }

在这里插入图片描述

3.2 导出数据库的架构

exportSchema: 这个参数是一个布尔值,用于指示是否应该导出数据库的架构。如果设置为 true,Room 会在编译时生成一个包含数据库架构的 JSON 文件。这对于调试和文档记录可能是有用的,但在生产环境中通常不需要。在这个例子中,它被设置为 false,意味着不会导出架构。

@Database(
    entities = [UserEntity::class],
    version = 1,
    exportSchema = false
)
abstract class MyDataBase:RoomDatabase() {

3.3 多个activity使用数据库

  1. 如下如果是多个activity,会使用到数据库,那么就需要增加如下这句代码。因为他是查询是将数据加载到内存的,所以如果这个时候有其他使用到数据库,那么数据就会出现不一致的问题,所以需要增加这句代码。
 Room.databaseBuilder(context,MyDataBase::class.java,"UserDb")
                     .enableMultiInstanceInvalidation()
                    .build()
                    .apply {
                        instance = this
                    }

四、项目中如何使用呢

其实就是如我们上面这样写,没有高级的工具
在这里插入图片描述
(1)多个表:entities可以这样写

    entities = [ProjectClassify::class, Article::class, HotKey::class, BannerBean::class,Almanac::class],

然后提供多个Dao
    abstract fun projectClassifyDao(): ProjectClassifyDao

    abstract fun browseHistoryDao(): BrowseHistoryDao

    abstract fun hotKeyDao(): HotKeyDao

    abstract fun bannerBeanDao(): BannerBeanDao

    abstract fun almanacDao(): AlmanacDao


大家,有兴趣,可以多上github找一些项目学习,看看别人是如何写的。

五、数据库迁移

如果我们想在这个表上增加一个字段,应该如何操作呢?

比如我们想增加一个foot字段

@Entity(tableName = "user")
data class UserEntity(
    @PrimaryKey(autoGenerate = true)
    val id: Int =0, // 改为非空
    @ColumnInfo
    val account: String,
    @ColumnInfo
    val nickname: String,
    @ColumnInfo
    val foot :Boolean
) 

新增字段,要对数据库的版本号进行提升。比如我们从1,提升到2

@Database(
    entities = [UserEntity::class],
    version = 2,
    exportSchema = false
)

只是修改这里还不行,我们还需要设置升级的策略。
(1)第一种:删除表,重新创建,暴力清除策略

abstract class MyDataBase:RoomDatabase() {

    companion object{
        private var instance:MyDataBase?=null //可空类型 在Kotlin中,默认情况下,所有基本数据类型(如 Int, Double 等)都是非空的

        fun getInstance(context:Context):MyDataBase{
            if (instance==null) {
                 Room.databaseBuilder(context,MyDataBase::class.java,"UserDb")
                     .enableMultiInstanceInvalidation()
                     .fallbackToDestructiveMigration()//暴力式清除
                    .build()
                    .apply {
                        instance = this
                    }

            }
            //当你有一个可空类型的变量,但在某个上下文中你知道它绝对不会是 null,你可以使用 !! 来告诉Kotlin编译器这个变量是非空的,并直接解引用它。但是,如果变量实际上是 null,使用 !! 会导致运行时异常
            return instance!!//非空断言 如果条件判断失败(即 instance 没有被成功初始化),这里就会抛出 NullPointerException。
        }


    }

    abstract fun getUserDao():UserDao

}

(2)自定义:你可以指定一个方式,比如你要新增,则写一个sql语句

val MIGRATION_1_2 = object :Migration(1,2){
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL(
            "ALTER TABLE user ADD COLUMN foot INTEGER NOT NULL DEFAULT 1 "
        )
    }

}
abstract class MyDataBase:RoomDatabase() {

    companion object{
        private var instance:MyDataBase?=null //可空类型 在Kotlin中,默认情况下,所有基本数据类型(如 Int, Double 等)都是非空的

        fun getInstance(context:Context):MyDataBase{
            if (instance==null) {
                 Room.databaseBuilder(context,MyDataBase::class.java,"UserDb")
                     .enableMultiInstanceInvalidation()
//                     .fallbackToDestructiveMigration()//暴力式清除
                     .addMigrations(MIGRATION_1_2)
                    .build()
                    .apply {
                        instance = this
                    }

            }
            //当你有一个可空类型的变量,但在某个上下文中你知道它绝对不会是 null,你可以使用 !! 来告诉Kotlin编译器这个变量是非空的,并直接解引用它。但是,如果变量实际上是 null,使用 !! 会导致运行时异常
            return instance!!//非空断言 如果条件判断失败(即 instance 没有被成功初始化),这里就会抛出 NullPointerException。
        }


    }

    abstract fun getUserDao():UserDao

}

好了,以上就是ROOM的基础内容了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

前期后期

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

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

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

打赏作者

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

抵扣说明:

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

余额充值