Android Jetpack系列---Room

前言

Room 在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库
Room 包含 3 个主要组件:
(1)数据库:包含数据库持有者,并作为应用已保留的持久关系型数据的底层连接的主要接入点

使用 @Database 注释的类应满足以下条件:
1.是扩展 RoomDatabase 的抽象类
2.在注释中添加与数据库关联的实体列表
3.包含具有 0 个参数且返回使用 @Dao 注释的类的抽象方法
在运行时,您可以通过调用 Room.databaseBuilder() 或Room.inMemoryDatabaseBuilder() 获取 Database 的实例

(2)Entity:表示数据库中的表
(3)DAO:包含用于访问数据库的方法

基本使用

(1)导入依赖:

    def room_version = "2.2.5"
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
    implementation "androidx.room:room-ktx:$room_version"
    testImplementation "androidx.room:room-testing:$room_version"

除此之外,不要忘记加上下面这个

apply plugin: 'kotlin-kapt'

(2)定义实体
对于每个实体,系统会在关联的 Database 对象中创建一个表,以存储这些项

//@Fts4:使用此注解支持全文搜索
@Entity(tableName = "user") //如不指定,默认是类名(SQLite中的表名称不区分大小写)
data class User(
    @PrimaryKey(autoGenerate = true) var id: Int,  //定义主键,并自动分配
    var name: String?,
    @ColumnInfo(name = "company_id") var companyId: String?, //指定列名称,默认是字段名
    @ColumnInfo(name = "company_name") var companyName: String?,
    @Ignore var overlook: String? //忽略字段
)

如果是复合主键,可以如此添加:

@Entity(primaryKeys = ["id", "companyId"])

如果想要将特定列编入索引,需要列出要在索引或复合索引中包含的列的名称,还可以将unique 属性设为 true,保证数据库中的某些字段或字段组必须是唯一的

@Entity(indices = [Index(value = ["company_name", "name"], unique = true)])

嵌套对象:可以使用 @Embedded 注释表示要分解为表格中的子字段的对象

@Entity
data class User(
    @PrimaryKey(autoGenerate = true) var id: Int,
    var name: String?,
    var companyId: String?,
    var companyName: String?,
    @Embedded var address: Address?
)

@Entity
data class Address(
    val country: String?,
    val province: String?,
    val city: String?
)

(3)DAO 访问数据

@Dao
interface UserDao {
    
    

    @Query("select * from user")
    fun getAllMsg(): List<User>

    @Query("select * from user where id in (:userId)")
    fun getAllById(userId: IntArray): List<User>

    @Query("select * from user where name like :userName")
    fun getAllByName(userName: String): List<User>

    @Query("select * from user where age < :youngAge")
    fun getYoungPeople(youngAge: Int): List<User>

    @Query("select * from user where age between :minAge and :maxAge")
    fun getPeopleBetweenAges(minAge: Int, maxAge: Int): List<User>

    @Query("select name, companyName from user")
    fun getColumn(): List<Name>

    //传递参数的集合
    @Query("select name, companyName from user where age in (:ages)")
    fun getPeopleByAge(ages: List<String>): List<Name>

    //流式响应式查询:只要表中的任何数据发生变化,返回的Flow对象就会再次触发查询并重新发出整个结果集
    @Query("select * from user")
    fun getAllUsers(): kotlinx.coroutines.flow.Flow<List<User>>

    //使用Flow响应式查询,只要对表中的任何行进行更新,Flow对象就会重新运行查询
    //通过将distinctUntilChanged()应用于返回的Flow对象,可以确保仅在实际查询结果发生更改时通知界面
    fun getUserDistinctUntilChanged() = getAllUsers().distinctUntilChanged()

    @Insert
    fun insertAll(vararg user: User)

    @Delete
    fun delete(user: User)

    //updateUser与每个实体的主键匹配的查询,也可以让此方法返回一个int值,以指示数据库中更新/删除的行数
    @Update
    fun updateUser(vararg user: User)

    //也可将suspend添加到DAO方法中,让其成为异步方法,这样可确保不会在主线程上执行这些方法
    @Query("select * from user")
    suspend fun getAllFromAsyn(): List<User>

    //使用LiveData进行可观察查询
    @Query("select * from user where id in (:userId)")
    fun getAllByIdFromLiveData(userId: IntArray): LiveData<List<User>>
}

(4)创建数据库
如果要增加work表,要进行数据库迁移,修改version

@Entity
data class Work(
    @PrimaryKey(autoGenerate = true) var id: Int,
    var name: String?
)
@Dao
interface WorkDao {
    
    
    @Query("select * from work")
    fun getAllMsg(): List<Work>

    @Insert
    fun insert(vararg work: Work)
}
@Database(entities = [User::class, Work::class], version = 2)
abstract class MyDatabase : RoomDatabase() {
    
    
    abstract val userDao: UserDao
    abstract val workDao: WorkDao

    companion object {
    
    
        @Volatile
        private var INSTANCE: MyDatabase? = null
        val MIGRATION = object : Migration(1, 2) {
    
     //增加表,迁移数据库
            override fun migrate(database: SupportSQLiteDatabase) {
    
    
                database.execSQL("CREATE TABLE `work` (`id` INTEGER NOT NULL, `name` TEXT ,PRIMARY KEY(`id`))")
            }
        }

        fun getInstance(): MyDatabase {
    
    
            synchronized(this) {
    
    
                var instance = INSTANCE
                if (instance == null) {
    
    
                    instance = Room.databaseBuilder(
                        MyApplication.getAppContext(),
                        MyDatabase::class.java,
                        "database"
                    ).allowMainThreadQueries().addMigrations(MIGRATION).build()
                }
                return instance
            }
        }
    }
}

(5)操作数据库

class MainActivity : AppCompatActivity() {
    
    
    private var user1: User? = null
    private var user2: User? = null
    private var user3: User? = null
    private var user4: User? = null
    private var userList: MutableList<User>? = null
    private var workList: MutableList<Work>? = null
    private var job: Work? = null

    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initAuthority()
        initData()
        operateDatabase()
    }

    private fun initData() {
    
    
        user1 = User(1, "一号嘉宾", "100", "百度", 10)
        user2 = User(2, "二号嘉宾", "200", "阿里", 20)
        user3 = User(3, "三号嘉宾", "300", "腾讯", 30)
        user4 = User(1, "行走的猪蹄", "900", "字节跳动", 50)
        job = Work(1, "程序员")
    }

    private fun operateDatabase() {
    
    
        insert.setOnClickListener {
    
    //插入数值
            MyDatabase.getInstance().userDao.insertAll(user1!!, user2!!, user3!!)
        }
        query.setOnClickListener {
    
    //查询年龄0-50
            userList = ArrayList()
            userList?.addAll(MyDatabase.getInstance().userDao.getPeopleBetweenAges(0, 50))
            txt.text = userList.toString()
        }
        update.setOnClickListener {
    
    //修改数据
            MyDatabase.getInstance().userDao.updateUser(user4!!)
        }
        delete.setOnClickListener {
    
    //删除数据
            MyDatabase.getInstance().userDao.delete(user2!!)
        }
        test.setOnClickListener {
    
    
            CoroutineScope(Dispatchers.Main).launch {
    
    //异步查询的情况
                userList = ArrayList()
                userList!!.addAll(MyDatabase.getInstance().userDao.getAllFromAsyn())
                txt.text = userList.toString()
            }
        }
        work.setOnClickListener {
    
    
//                MyDatabase.getInstance().workDao.insert(job!!)//插入数据后进行显示
            workList = ArrayList()
            workList!!.addAll(MyDatabase.getInstance().workDao.getAllMsg())
            txt.text = workList.toString()
        }
    }

    private fun initAuthority() {
    
    
        PermissionX.init(this)
            .permissions(
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            )
            .request {
    
     allGranted, grantedList, deniedList ->
                if (allGranted) {
    
    
                    Toast.makeText(this, "All permissions are granted", Toast.LENGTH_LONG).show()
                } else {
    
    
                    Toast.makeText(
                        this,
                        "These permissions are denied: $deniedList",
                        Toast.LENGTH_LONG
                    ).show()
                }
            }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_45485851/article/details/108869629