Android Room怎么使用

今天小编给大家分享一下Android Room怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    @ForeignKey和@PrimaryKey

    考验你数据库知识的时候来了!因为你会频繁看到@PrimaryKey所以先讲它

    @ForeignKey 注解用于定义外键关系,它指定了一个实体类中的一个字段是另一个实体类的主键。这种关系被称为“外键关系”,并且可以用于在多个表之间建立关联。

    例如,如果有两个实体类 UserAddress,并且想要将它们关联起来,则可以使用 @ForeignKey 注解来指定 Address 中的 user_id 字段是 User 的主键:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        val name: String
    )
    @Entity(tableName = "addresses",
            foreignKeys = [
                ForeignKey(entity = User::class,
                           parentColumns = ["id"],
                           childColumns = ["user_id"],
                           onDelete = ForeignKey.CASCADE)
            ])
    data class Address(
        @PrimaryKey val id: Int,
        val street: String,
        val city: String,
        val state: String,
        val zip: String,
        @ColumnInfo(name = "user_id") val userId: Int
    )

    在这个例子中,我们使用 @ForeignKey 注解将 Address 中的 user_id 字段指定为 User 的主键。这将创建一个外键关系,确保在插入或更新 Address 表中的数据时,user_id 字段的值必须是 User 表中存在的主键值之一。

    @PrimaryKey 注解用于指定实体类中的一个字段是主键。主键是用于唯一标识每个实体类对象的字段。在 Room 中,每个实体类必须至少有一个字段被指定为主键。

    例如,如果有一个实体类 User,并且想要将 id 字段指定为主键,则可以使用 @PrimaryKey 注解:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        val name: String
    )

    在这个例子中,我们使用 @PrimaryKey 注解将 id 字段指定为 User 实体类的主键。这将确保在插入或更新 User 表中的数据时,每个 id 字段的值都是唯一的。

    @TypeConverters

    在使用Room时,你可能会遇到需要在Entity类中使用非基本类型的情况,例如Date、Calendar、List等类型。在这种情况下,你可以使用TypeConverters将这些类型转换为Room可以存储的类型。在Room中,可以使用@TypeConverter注解来定义一个类型转换器,例如:

    class Converters {
        @TypeConverter
        fun fromDate(date: Date): Long {
            return date.time
        }
        @TypeConverter
        fun toDate(timestamp: Long): Date {
            return Date(timestamp)
        }
        @TypeConverter
        fun fromList(list: List<String>?): String? {
            return list?.joinToString(",")
        }
        @TypeConverter
        fun toList(string: String?): List<String>? {
            return string?.split(",")
        }
    }
    @Entity(tableName = "user")
    @TypeConverters(Converters::class)
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        val birthday: Date
      	@TypeConverters(HobbiesConverter::class) val hobbies: List<String>
    )
    @Database(entities = [User::class], version = 1)
    @TypeConverters(Converters::class)
    abstract class AppDatabase : RoomDatabase() {
        // ...
    }
    @Dao
    @TypeConverters(Converters::class)
    interface UserDao {
        @Query("SELECT * FROM user")
        fun getAll(): List<User>
    }

    示例代码在非常多的地方使用了@TypeConverters ,不同的位置造成的影响也是不同的,实际上可以应用到以下四个地方:

    • 实体类:在 @Entity 注解中使用,可以在处理该实体类时使用它们。

    • DAO 接口:在 DAO 接口中使用,可以在执行该 DAO 中的查询时使用它们。

    • 数据库类:在 RoomDatabase 类中使用, 可以在整个数据库中使用它们。

    • 实体类中的属性:在实体类中的属性,可以在处理该属性时使用指定的类型转换器

    @Relation

    @Relation 用于在实体类之间建立关系。它可以用于定义两个或更多实体之间的关系,这些实体可以在数据库中分别存储在不同的表中。

    @Relation 注解应该与 @Query 注解一起使用,以便 Room 可以在查询结果中返回相关实体之间的关系。@Relation 注解的一个常见用例是定义父子关系,其中一个实体包含对另一个实体的引用。

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        val email: String
    )
    @Entity(tableName = "books")
    data class Book(
        @PrimaryKey val id: Int,
        val title: String,
        val author: String,
        val userId: Int
    )
    data class UserWithBooks(
        @Embedded val user: User,
        @Relation(
            parentColumn = "id",
            entityColumn = "userId"
        )
        val books: List<Book>
    )

    在这个示例中,我们有两个实体类 UserBook,它们之间有一个父子关系,其中一个用户可以拥有多本书。然后,我们定义了一个 UserWithBooks 数据类,它包含一个嵌套的 User 实体和一个 @Relation 注解,用于指定如何检索与该用户关联的所有书籍。@Relation 注解包括 parentColumnentityColumn 参数,分别指定父实体的主键列和子实体的外键列。

    当我们使用 @Relation 注解时,我们需要在查询中使用 SELECT 语句,以便 Room 可以检索相关的实体。例如,在 Dao 接口中,我们可以使用以下查询:

    //Transaction下一点就会说
    @Transaction
    @Query("SELECT * FROM users WHERE id = :id")
    fun getUserWithBooks(id: Int): UserWithBooks

    此外,我们使用 SELECT * 语句来检索所有用户属性和相关的书籍列表,因为 UserWithBooks 数据类包含一个嵌套的 User 实体和一个 List<Book> 列表。

    @Transaction

    第4点说到@Relation时使用到了@Transaction。在这个查询中,我们使用 @Transaction 注解来确保整个查询作为一个事务执行,以便 Room 可以在单个操作中检索 User 实体和与之相关的所有 Book 实体。

    @Transaction用于将一组数据库操作包装在一个事务中。它可以确保在执行数据库操作时保持数据库的一致性,并在必要时回滚事务以确保数据的完整性。

    在 Room 中,单个数据库操作(例如插入、更新或删除)是自动运行在事务中的。但是,当需要执行多个数据库操作时,可能需要手动创建一个事务来确保这些操作原子性地执行。如果需要执行多个数据库操作,请始终考虑使用 @Transaction 注解。这可以避免数据不一致和其他与数据库操作相关的问题。

    @Embedded

    @Embedded用于指定一个实体类中的一个或多个字段应该作为其所属的另一个实体的嵌入式对象。这使得 Room 可以将多个相关实体的数据组合成一个单独的对象,从而简化了数据库操作。

    当在一个实体类中使用 @Embedded 注解时,可以指定该实体类中的一个或多个字段应该嵌入到另一个实体类中。例如,假设有一个 Address 实体类和一个 User 实体类,其中 User 实体类包含一个 Address 对象。可以使用 @Embedded 注解将 Address 对象嵌入到 User 实体类中:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        @Embedded val address: Address
    )
    data class Address(
        val street: String,
        val city: String,
        val state: String,
        val zip: String
    )

    在这个例子中,User 实体类包含一个 Address 对象,它使用 @Embedded 注解指定了该对象应该嵌入到 User 实体类中。在查询数据库时,Room 将自动组合 User 实体类和 Address 实体类中的字段,以便可以轻松地访问和操作它们。

    还可以使用 prefix 参数来指定 Room 应该在组合两个实体类中的字段时使用的前缀。例如:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        @Embedded(prefix = "home_") val homeAddress: Address,
        @Embedded(prefix = "work_") val workAddress: Address
    )

    在这个例子中,User 实体类包含两个 Address 对象,一个是 homeAddress,另一个是 workAddress。我们使用 @Embedded(prefix = "home_")@Embedded(prefix = "work_") 注解为每个地址对象指定了不同的前缀。这使得 Room 可以区分两个地址对象中的相同字段,并将它们组合成一个单独的对象。

    当然你也可以这么干

    @Entity(tableName 
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        @Embedded @ColumnInfo(name = "home_address") val homeAddress: Address
    )

    @ColumnInfo

    可以看到,我们刚刚用到了@ColumnInfo这个注解,用于自定义实体类中的列名、默认值和其他属性。当需要将一个实体类映射到数据库表时,可以使用 @ColumnInfo 注解来指定实体类中的每个字段在数据库表中的名称和其他属性。

    (1)指定实体类中的字段名称

    @ColumnInfo 注解最常用的用途是指定实体类中的字段名称。例如:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        @ColumnInfo(name = "full_name") val name: String,
        val age: Int
    )

    在这个例子中,我们使用 @ColumnInfo(name = "full_name")name 字段的名称指定为 full_name。这意味着在数据库表中,这个字段将被命名为 full_name,而不是 name

    (2)指定实体类中的字段默认值

    @ColumnInfo 注解还可以用于指定实体类中的字段默认值。例如:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        @ColumnInfo(name = "full_name") val name: String,
        @ColumnInfo(name = "is_active") val isActive: Boolean = true
    )

    在这个例子中,我们使用 @ColumnInfo(name = "is_active")isActive 字段的名称指定为 is_active,并将其默认值设置为 true。这意味着在数据库表中,这个字段将被命名为 is_active,并且默认值将为 true

    (3)指定实体类中的字段约束

    @ColumnInfo 注解还可以用于指定实体类中的字段约束。例如:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        @ColumnInfo(name = "full_name") val name: String,
        @ColumnInfo(name = "is_active") val isActive: Boolean = true,
        @ColumnInfo(name = "created_at", defaultValue = "CURRENT_TIMESTAMP") val createdAt: String
    )

    在这个例子中,我们使用 @ColumnInfo(name = "created_at", defaultValue = "CURRENT_TIMESTAMP")createdAt 字段的名称指定为 created_at,并将其默认值设置为 CURRENT_TIMESTAMP。这意味着在数据库表中,这个字段将被命名为 created_at,并且默认值将为 CURRENT_TIMESTAMP

    @Ignore

    很直观的注解哈。指定实体类中应该忽略的字段。当需要在实体类中添加一个字段,但不想将其映射到数据库表中时,可以使用 @Ignore 注解来指定该字段应该被忽略。

    忽略一个实体类中的字段

    @Ignore 注解最常用的用法是忽略一个实体类中的字段,从而防止该字段被映射到数据库表中。例如:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        @Ignore val password: String
    )

    在这个例子中,我们使用 @Ignorepassword 字段指定为应该被忽略的字段。这意味着在数据库表中,这个字段将不会出现,也不会被映射到 User 实体类中。

    (1)忽略一个实体类中的 getter 和 setter 方法

    除了忽略一个实体类中的字段外,@Ignore 注解还可以用于忽略一个实体类中的 getter 和 setter 方法。这可以帮助控制 Room 如何处理实体类中的方法。

    例如,如果希望 Room 不生成一个实体类中的 setter 方法,则可以将 @Ignore 注解添加到该方法上:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        val password: String
    ) {
        @Ignore
        fun setPassword(password: String) {
            // ...
        }
    }

    在这个例子中,我们使用 @IgnoresetPassword 方法指定为应该被忽略的方法。这意味着 Room 不会生成一个 setter 方法来设置 password 字段的值。

    (2)忽略一个实体类中的整个构造函数

    最后,@Ignore 注解还可以用于忽略一个实体类中的整个构造函数。这可以帮助控制 Room 如何处理实体类中的构造函数。

    例如,如果希望 Room 不使用默认的构造函数来创建实体类的实例,则可以使用 @Ignore 注解标记该构造函数:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        val password: String
    ) {
        @Ignore
        constructor(id: Int, name: String) : this(id, name, "")
    }

    在这个例子中,我们使用 @Ignore 将第二个构造函数指定为应该被忽略的构造函数。这意味着 Room 不会使用这个构造函数来创建 User 实体类的实例。

    @Index

    考验你数据库知识的时候来了!索引(个索引、多个索引、复合索引)可以提高数据库表查询的性能,因为它们使数据库系统能够更快地查找和排序表中的数据。

    (1)在一个实体类中创建单个索引

    @Index 注解最常用的用法是在一个实体类中创建单个索引。例如:

    @Entity(tableName = "users", indices = [Index(value = ["name"])])
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        val age: Int
    )

    在这个例子中,我们使用 @Index 注解在 name 字段上创建了一个单个索引。这将使数据库系统能够更快地查找和排序 User 表中的数据。

    (2)在一个实体类中创建多个索引

    除了在一个实体类中创建单个索引外,@Index 注解还可以用于在一个实体类中创建多个索引。例如:

    @Entity(tableName = "users", indices = [
        Index(value = ["name"]),
        Index(value = ["age"])
    ])
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        val age: Int
    )

    在这个例子中,我们使用 @Index 注解在 nameage 字段上创建了两个索引。这将使数据库系统能够更快地查找和排序 User 表中的数据。

    (3)在一个实体类中创建复合索引

    @Index 注解还可以用于在一个实体类中创建复合索引。复合索引是指将多个字段组合在一起以创建一个索引,这将使数据库系统能够更快地查找和排序这些字段的组合。

    例如,如果希望在 User 表中按照 nameage 字段的组合进行排序,则可以使用 @Index 注解来创建一个复合索引:

    @Entity(tableName = "users", indices = [
        Index(value = ["name", "age"])
    ])
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        val age: Int
    )

    在这个例子中,我们使用 @Index 注解在 nameage 字段上创建了一个复合索引。这将使数据库系统能够更快地查找和排序 User 表中按照 nameage 字段的组合进行排序的数据。

    @Entity

    当在 Room 中定义一个实体类时,必须使用 @Entity 注解来指定该类应该被映射到数据库中的哪个表。

    (1)在一个实体类中指定表名

    @Entity 注解最常用的用法是在一个实体类中指定表名。例如:

    @Entity(tableName = "users")
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        val age: Int
    )

    在这个例子中,我们使用 @Entity 注解将 User 实体类映射到名为 users 的数据库表中。这将使 Room 能够将 User 类中的字段映射到数据库表中的相应列中。

    (2)在一个实体类中指定索引

    除了在一个实体类中指定表名外,@Entity 注解还可以用于在一个实体类中指定索引。索引可以提高数据库表查询的性能,因为它们使数据库系统能够更快地查找和排序表中的数据。

    例如,如果希望在 User 表中按照 name 字段进行排序,则可以使用 @Entity 注解来创建一个索引:

    @Entity(tableName = "users", indices = [Index(value = ["name"])])
    data class User(
        @PrimaryKey val id: Int,
        val name: String,
        val age: Int
    )

    在这个例子中,我们使用 @Entity 注解在 name 字段上创建了一个索引。这将使数据库系统能够更快地查找和排序 User 表中的数据。

    (3)在一个实体类中指定继承关系

    最后,@Entity 注解还可以用于在一个实体类中指定继承关系。如果的实体类继承自另一个实体类,则可以使用 @Entity 注解来指定它们之间的关系。

    例如,如果有一个 Person 实体类和一个 Employee 实体类,Employee 实体类继承自 Person 实体类,则可以使用 @Entity 注解来指定它们之间的关系:

    @Entity(tableName = "user")
    open class User(
        @PrimaryKey val id: Int,
        val name: String
    )
    @Entity(tableName = "employees")
    data class Employee(
        @PrimaryKey val id: Int,
        val salary: Int,
        @ColumnInfo(name = "user_id") val userId: Int
    ) : User(userId, "")

    在这个例子中,我们使用 @Entity 注解将 Person 实体类映射到名为 people 的数据库表中,并将 Employee 实体类映射到名为 employees 的数据库表中。此外,我们还使用 @Entity 注解指定了 Employee 实体类继承自 Person 实体类,并使用 @ColumnInfo 注解将 person_id 字段指定为 Employee 表中的外键。这将确保在插入或更新 Employee 表中的数据时,person_id 字段的值必须是 Person 表中存在的主键值之一。

    @Dao

    @Dao 是用于访问数据库中数据的一种抽象层。在 Room 中,每个 DAO 都定义了一组用于与数据库进行交互的方法。意思是就这么用,没啦。

    @Dao
    interface UserDao {}

    @Database

    @Database 注解是 Room 中的一个注解,用于定义数据库类。当在 Room 中定义一个数据库时,必须使用 @Database 注解来指定该数据库包含哪些实体类和版本号等信息。

    (1)在一个类中定义数据库实例

    @Database 注解最常用的用法是在一个类中定义数据库实例。例如:

    @Database(entities = [User::class], version = 1)
    abstract class AppDatabase : RoomDatabase() {
        abstract fun userDao(): UserDao
    }

    在这个例子中,我们使用 @Database 注解定义了一个数据库类 AppDatabase,并在其中指定了包含 User 实体类的数据库版本号。此外,我们还定义了一个抽象方法 userDao(),用于返回一个 UserDao 数据访问对象 (DAO)。

    (2)指定多个实体类

    @Database 注解还可以用于指定多个实体类。例如:

    @Database(entities = [User::class, Address::class], version = 1)
    abstract class AppDatabase : RoomDatabase() {
        abstract fun userDao(): UserDao
        abstract fun addressDao(): AddressDao
    }

    在这个例子中,我们使用 @Database 注解指定了包含 UserAddress 实体类的数据库版本号。然后,我们定义了两个抽象方法 userDao()addressDao(),分别用于返回 UserDaoAddressDao 数据访问对象 (DAO)。

    (3)指定数据库升级策略

    最后,@Database 注解还可以用于指定数据库升级策略。当升级数据库时,可能需要指定一些操作来处理数据模式的变化。Room 提供了两种升级策略:MigrateFallbackToDestructiveMigration

    例如,如果希望在升级数据库时保留现有数据,可以使用 Migrate 升级策略:

    val migration1to2 = object : Migration(1, 2) {
        override fun migrate(database: SupportSQLiteDatabase) {
            // TODO: write migration code here
        }
    }
    @Database(entities = [User::class], version = 2, migrations = [migration1to2])
    abstract class AppDatabase : RoomDatabase() {
        abstract fun userDao(): UserDao
    }

    在这个例子中,我们使用 Migrate 升级策略将数据库版本从 1 升级到 2。我们定义了一个名为 migration1to2 的迁移对象,用于在升级数据库时执行自定义的 SQL 语句。然后,我们使用 @Database 注解指定了包含 User 实体类的数据库版本号和升级策略。

    如果不需要保留现有数据,可以使用 FallbackToDestructiveMigration 升级策略:

    @Database(entities = [User::class], version = 2, exportSchema = false)
    abstract class AppDatabase : RoomDatabase() {
        abstract fun userDao(): UserDao
        companion object {
            @Volatile
            private var instance: AppDatabase? = null
            fun getInstance(context: Context): AppDatabase {
                return instance ?: synchronized(this) {
                    instance ?: buildDatabase(context).also { instance = it }
                }
            }
            private fun buildDatabase(context: Context): AppDatabase {
                return Room.databaseBuilder(context, AppDatabase::class.java, "app-database")
                    .fallbackToDestructiveMigration().build()
            }
        }
    }

    在这个例子中,我们使用 FallbackToDestructiveMigration 升级策略将数据库版本从 1 升级到 2。我们使用 @Database 注解指定了包含 User 实体类的数据库版本号和升级策略,并将 exportSchema 参数设置为 false,以避免生成不必要的 JSON 文件。

    @Query

    用于定义SQL查询语句,可以在之前的例子中找到,许多的@Query的身影 (考验你数据库基础的时候到了!)

    (1)基本查询操作

    @Query 注解最常用的用法是执行基本的查询操作。例如:

    @Dao
    interface UserDao {
        @Query("SELECT * FROM users")
        fun getAllUsers(): List<User>
    }

    在这个例子中,我们使用 @Query 注解定义了一个基本的 SQL 查询语句,该语句将返回 users 表中的所有数据。我们将此查询定义为 getAllUsers() 方法的一部分,以便在需要时调用该方法。

    (2)带参数的查询操作

    @Query 注解还可以用于执行带参数的查询操作。例如:

    @Dao
    interface UserDao {
        @Query("SELECT * FROM users WHERE id = :id")
        fun getUserById(id: Int): User
    }

    在这个例子中,我们使用 @Query 注解定义了一个带有参数的 SQL 查询语句,该语句将返回 users 表中 id 字段等于给定值的数据。我们将此查询定义为 getUserById() 方法的一部分,并将 id 参数传递给查询语句。

    (3)使用关联查询

    最后,@Query 注解还可以用于执行关联查询。关联查询是一种可以跨多个表查询数据的查询类型。

    @Dao
    interface UserDao {
        @Query("SELECT * FROM users INNER JOIN addresses ON users.address_id = addresses.id")
        fun getUsersWithAddresses(): List<UserWithAddress>
    }

    在这个例子中,我们使用 @Query 注解定义了一个关联查询语句,该语句将返回 users 表中的数据以及与之关联的 addresses 表中的数据。我们将此查询定义为 getUsersWithAddresses() 方法的一部分,并使用 INNER JOIN 子句指定 users 表和 addresses 表之间的关系。

    @Insert、@Update、@Delete

    顾名思义哈,也就不用举例了,嘻嘻嘻

    @Dao
    interface UserDao {
        @Insert\@Update\@Delete
        fun xxxUser(user: User)
    }

    多数据源

    使用Kotlin Flow可以很方便地处理多个数据源的情况。在使用Room时,我们可以在Repository层中实现本地和远程数据源的逻辑,并使用Kotlin Flow来组合和转换数据。

    以下是一个示例,演示了如何使用Room和Kotlin Flow处理多个数据源的情况:

    class UserRepository(
        private val userDao: UserDao,
        private val api: ApiService
    ) {
        fun getUsers(): Flow<List<User>> {
            val localUsers = userDao.getAll().asFlow()
            val remoteUsers = api.getUsers().asFlow()
            return localUsers.combine(remoteUsers) { local, remote ->
                // 合并本地和远程数据
                (local + remote).distinctBy { it.id }
            }
        }
        suspend fun updateUser(user: User) {
            api.updateUser(user.id, user)
            userDao.update(user)
        }
    }

    在以上示例中,我们在UserRepository中使用了本地和远程数据源,并使用Kotlin Flow.combine操作符将本地和远程数据源合并在一起,并在最后返回一个Flow对象。我们还使用了suspend修饰符将updateUser方法标记为挂起函数,以便可以在协程中执行异步操作。

    很方便吧

    @Fts3和@Fts4

    这个一般用不到来着,不过如果你要做小说软件的话,可能有用。用于创建全文本搜索虚拟表。全文本搜索是一种在大型文本数据集中搜索特定文本片段的技术。当您需要在应用程序中实现全文本搜索时,可以使用这两个注解来创建虚拟表。

    (1)@Fts3 注解

    @Fts3 注解用于创建一个基于 SQLite FTS3 算法的虚拟表。例如:

    @Fts3
    @Entity(tableName = "books")
    data class Book(
        @ColumnInfo(name = "book_title") val title: String,
        @ColumnInfo(name = "book_author") val author: String,
        @ColumnInfo(name = "book_description") val description: String
    )

    在这个例子中,我们使用 @Fts3 注解定义了一个名为 books 的虚拟表。该表将基于 titleauthordescription 列的内容创建一个全文本索引。当您执行全文本搜索时,将使用该索引来查找与搜索查询匹配的行。

    (2)@Fts4 注解

    @Fts4 注解用于创建一个基于 SQLite FTS4 算法的虚拟表。例如:

    @Fts4(contentEntity = Book::class)
    @Entity(tableName = "book_fts")
    data class BookFts(
        @ColumnInfo(name = "book_fts_title") val title: String,
        @ColumnInfo(name = "book_fts_author") val author: String,
        @ColumnInfo(name = "book_fts_description") val description: String
    )

    在这个例子中,我们使用 @Fts4 注解定义了一个名为 book_fts 的虚拟表。该表将基于 titleauthordescription 列的内容创建一个全文本索引。与 @Fts3 注解不同的是,@Fts4 注解需要使用 contentEntity 参数指定要创建索引的实体类。

    (3)使用全文本搜索

    创建全文本搜索虚拟表后,您可以使用 Room 中的 MATCH 关键字来执行全文本搜索。例如:

    @Dao
    interface BookDao {
        @Query("SELECT * FROM books WHERE books MATCH :query")
        fun searchBooks(query: String): List<Book>
    }

    在这个例子中,我们使用 MATCH 关键字来执行全文本搜索操作。该操作将在 books 虚拟表中搜索与 query 参数匹配的行,并返回所有匹配的结果。注意,在使用这些注解时,请确保为要搜索的列创建了索引,以避免搜索操作变得缓慢或不可用。

    以上就是“Android Room怎么使用”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程之家行业资讯频道。

    版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

    相关推荐


    更新Android SDK到3.0版本时,遇到Failed to rename directory E:\android\tools to E:\android\temp\ToolPackage.old01问题,导致无法更新,出现该问题的原因是由于3.0版本与较早的sdk版本之间文件结构有冲突,解决
    Android 如何解决dialog弹出时无法捕捉Activity的back事件 在一些情况下,我们需要捕捉back键事件,然后在捕捉到的事件里写入我们需要进行的处理,通常可以采用下面三种办法捕捉到back事件: 1)重写onKeyDown或者onKeyUp方法 2)重写onBackPressed方
    Android实现自定义带文字和图片的Button 在Android开发中经常会需要用到带文字和图片的button,下面来讲解一下常用的实现办法。一.用系统自带的Button实现 最简单的一种办法就是利用系统自带的Button来实现,这种方式代码量最小。在Button的属性中有一个是drawable
    Android中的&quot;Unable to start activity ComponentInfo&quot;的错误 最近在做一款音乐播放器的时候,然后在调试的过程中发现一直报这个错误&quot;Unable to start activity ComponentInfo&quot;,从字面
    Android 关于长按back键退出应用程序的实现最近在做一个Android上的应用,碰到一个问题就是如何实现长按back键退出应用程序。在网上查找了很多资料,发现几乎没有这样的实现,大部分在处理时是双击back键来退出应用程序。参考了一下双击back键退出应用程序的代码,网上主流的一种方法是下面
    android自带的时间选择器只能精确到分,但是对于某些应用要求选择的时间精确到秒级,此时只有自定义去实现这样的时间选择器了。下面介绍一个可以精确到秒级的时间选择器。 先上效果图: 下面是工程目录: 这个控件我也是用的别人的,好像是一个老外写的,com.wheel中的WheelView是滑动控件的主
    Android平台下利用zxing实现二维码开发 现在走在大街小巷都能看到二维码,而且最近由于项目需要,所以研究了下二维码开发的东西,开源的二维码扫描库主要有zxing和zbar,zbar在iPos平台上应用比较成熟,而在Android平台上主流还是用zxing库,因此这里主要讲述如何利用zxing
    Android ListView的item背景色设置以及item点击无响应等相关问题 在Android开发中,listview控件是非常常用的控件,在大多数情况下,大家都会改掉listview的item默认的外观,下面讲解以下在使用listview时最常见的几个问题。1.如何改变item的背景色和按
    如何向Android模拟器中导入含有中文名称的文件在进行Android开发的时候,如果需要向Android模拟器中导入文件进行测试,通过DDMS下手动导入或者在命令行下通过adb push命令是无法导入含有中文文件名的文件的。后来发现借用其他工具可以向模拟器中导入中文名称的文件,这个工具就是Ultr
    Windows 下搭建Android开发环境一.下载并安装JDK版本要求JDK1.6+,下载JDK成功后进行安装,安装好后进行环境变量的配置【我的电脑】-——&gt;【属性】——&gt;【高级】 ——&gt;【环境变量】——&gt;【系统变量】中点击【新建】:变量名:CLASSPATH变量值:……
    如何利用PopupWindow实现弹出菜单并解决焦点获取以及与软键盘冲突问题 在android中有时候可能要实现一个底部弹出菜单,此时可以考虑用PopupWindow来实现。下面就来介绍一下如何使用PopupWindow实现一个弹出窗。 主Activity代码:public void onCreat
    解决Android中的ERROR: the user data image is used by another emulator. aborting的方法 今天调试代码的时候,突然出现这个错误,折腾了很久没有解决。最后在google上找到了大家给出的两种解决方案,下面给出这两种方法的链接博客:ht
    AdvserView.java package com.earen.viewflipper; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory;
    ImageView的scaleType的属性有好几种,分别是matrix(默认)、center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY。 |值|说明| |:--:|:--| |center|保持原图的大小,显示在ImageVie
    文章浏览阅读8.8k次,点赞9次,收藏20次。本文操作环境:win10/Android studio 3.21.环境配置 在SDK Tools里选择 CMAKE/LLDB/NDK点击OK 安装这些插件. 2.创建CMakeLists.txt文件 在Project 目录下,右键app,点击新建File文件,命名为CMakeLists.txt点击OK,创建完毕! 3.配置文件 在CMa..._link c++ project with gradle
    文章浏览阅读1.2w次,点赞15次,收藏69次。实现目的:由mainActivity界面跳转到otherActivity界面1.写好两个layout文件,activity_main.xml和otherxml.xmlactivity_main.xml&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;RelativeLayout ="http://schemas..._android studio 界面跳转
    文章浏览阅读3.8w次。前言:最近在找Android上的全局代理软件来用,然后发现了这两款神作,都是外国的软件,而且都是开源的软件,因此把源码下载了下来,给有需要研究代理这方面的童鞋看看。不得不说,国外的开源精神十分浓,大家相互使用当前基础的开源软件,然后组合成一个更大更强的大开源软件。好吧,废话不多说,下面简单介绍一下这两款开源项目。一、ProxyDroid:ProxyDroid功能比较强大,用到的技术也比较多,源码也_proxydroid
    文章浏览阅读2.5w次,点赞17次,收藏6次。创建项目后,运行项目时Gradle Build 窗口却显示错误:程序包R不存在通常情况下是不会出现这个错误的。我是怎么遇到这个错误的呢?第一次创建项目,company Domain我使用的是:aven.com,但是创建过程在卡在了Building 'Calculator' Gradle Project info这个过程中,于是我选择了“Cancel”第二次创建项目,我还是使用相同的项目名称和项目路_r不存在
    文章浏览阅读8.9w次,点赞4次,收藏43次。前言:在Android上使用系统自带的代理,限制灰常大,仅支持系统自带的浏览器。这样像QQ、飞信、微博等这些单独的App都不能使用系统的代理。如何让所有软件都能正常代理呢?ProxyDroid这个软件能帮你解决!使用方法及步骤如下:一、推荐从Google Play下载ProxyDroid,目前最新版本是v2.6.6。二、对ProxyDroid进行配置(基本配置:) (1) Auto S_proxydroid使用教程
    文章浏览阅读1.1w次,点赞4次,收藏17次。Android Studio提供了一个很实用的工具Android设备监视器(Android device monitor),该监视器中最常用的一个工具就是DDMS(Dalvik Debug Monitor Service),是 Android 开发环境中的Dalvik虚拟机调试监控服务。可以进行的操作有:为测试设备截屏,查看特定进程中正在运行的线程以及堆栈信息、Logcat、广播状态信息、模拟电话_安卓摄像头调试工具