快速了解Android Room使用细则进阶

目录
  • 1、前言
  • 2、@ForeignKey和@PrimaryKey
  • 3、@TypeConverters
  • 4、@Relation
  • 5、@Transaction
  • 6、@Embedded
  • 7、@ColumnInfo
    • (1)指定实体类中的字段名称
    • (2)指定实体类中的字段默认值
    • (3)指定实体类中的字段约束
  • 8、@Ignore
    • 忽略一个实体类中的字段
    • (1)忽略一个实体类中的 getter 和 setter 方法
    • (2)忽略一个实体类中的整个构造函数
  • 9、@Index
    • (1)在一个实体类中创建单个索引
    • (2)在一个实体类中创建多个索引
    • (3)在一个实体类中创建复合索引
  • 10、@Entity
    • (1)在一个实体类中指定表名
    • (2)在一个实体类中指定索引
    • (3)在一个实体类中指定继承关系
  • 11、@Dao
  • 12、@Database
    • (1)在一个类中定义数据库实例
    • (2)指定多个实体类
    • (3)指定数据库升级策略
  • 13、@Query
    • (1)基本查询操作
    • (2)带参数的查询操作
    • (3)使用关联查询
  • 14、@Insert、@Update、@Delete
  • 15、多数据源
  • 16、@Fts3和@Fts4
    • (1)@Fts3 注解
    • (2)@Fts4 注解
    • (3)使用全文本搜索
  • 总结

1、前言

上一篇5分钟带你了解Android Room数据好起来了,有人催更,遂决定再写一篇Room的使用,这篇我们着重讲讲注解。如果写的不好,或者有错误之处,恳请在评论、私信、邮箱指出,万分感谢

2、@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 字段的值都是唯一的。

3、@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 类中使用, 可以在整个数据库中使用它们。
  • 实体类中的属性:在实体类中的属性,可以在处理该属性时使用指定的类型转换器

4、@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> 列表。

5、@Transaction

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

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

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

6、@Embedded

上一篇,有同志说@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
)

7、@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

8、@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 实体类的实例。

9、@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 字段的组合进行排序的数据。

10、@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 表中存在的主键值之一。

11、@Dao

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

@Dao
interface UserDao {}

12、@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 文件。

13、@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 表之间的关系。

14、@Insert、@Update、@Delete

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

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

15、多数据源

使用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方法标记为挂起函数,以便可以在协程中执行异步操作。

很方便吧

16、@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 参数匹配的行,并返回所有匹配的结果。注意,在使用这些注解时,请确保为要搜索的列创建了索引,以避免搜索操作变得缓慢或不可用。

总结

我们在这一篇提到了17个注释,,我们可以使用以上注解来定义实体类、DAO接口和数据库,并实现各种数据操作和类型转换。这些注解可以帮助我们更好地使用Room进行开发,并实现更加复杂和高效的功能,涵盖了绝大数开发的需求。当然,在实际开发中,我们还需要根据具体的业务需求和技术特点来选择合适的方案和实现方式。

实际上,Room的应用远不止如此,如果有人感兴趣的话,我就继续出下一期吧!

感谢

  • 校稿:ChatGpt/Bing
  • 文笔优化:ChatGpt/Bing/秘塔写作猫

以上就是快速了解Android Room使用细则进阶的详细内容,更多关于Android Room使用细则的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android Jetpack组件支持库DataBinding与ViewModel与LiveData及Room详解

    目录 一.官方推荐的Jetpack架构 二.添加依赖 三.创建Repository 四.创建ViewModel 五.activity中使用 Android Jetpack之ViewModel.LiveData Android Jetpack之LifeCycle 一.官方推荐的Jetpack架构 ViewModel是介于View(视图)和Model(数据模型)之间的中间层,能够使视图和数据分离,又能提供视图和数据之间的通信. LiveData是一个能够在ViewModel中数据发生变化时通知页面刷

  • Android Room数据库加密详解

    本文实例为大家分享了Android Room之数据库加密的具体实现,供大家参考,具体内容如下 一.需求背景 Android平台自带的SQLite有一个致命的缺陷:不支持加密.这就导致存储在SQLite中的数据可以被任何人用任何文本编辑器查看到.如果是普通的数据还好,但是当涉及到一些账号密码,或者聊天内容的时候,我们的应用就会面临严重的安全漏洞隐患. 二.加密方案 1.在数据存储之前进行加密,在加载数据之后再进行解密,这种方法大概是最容易想的到,而且也不能说这种方式不好,就是有些比较繁琐. 如果项

  • Android使用Room操作数据库流程详解

    目录 1. 创建实体类User 2. 创建DAO 3. 数据库 4. 使用 Room的三个主要组件: 数据库类,用于保存数据库并作为应用持久性数据底层连接的主要访问点. 数据实体,@Entity,表示数据库中的表. 数据访问对象 (DAO),@Dao,提供查询.更新.插入和删除数据的方法. build.gradle添加 dependencies {    def room_version = "2.4.3" implementation "android.arch.persi

  • Android开发Jetpack组件Room用例讲解

    目录 一.简介 二.导入 三.使用 3.1 创建 Entity 类 3.2 创建 Dao 类 3.3 创建 Database 抽象类 3.4 测试 四.数据库升级 4.1 简单升级 4.2 规范升级 4.2.1 新增一张表 4.2.2 修改一张表 4.3 测试 一.简介 Room 是 Google 官方推出的数据库 ORM 框架.ORM 是指 Object Relational Mapping,即对象关系映射,也就是将关系型数据库映射为面向对象的语言.使用 ORM 框架,我们就可以用面向对象的思

  • Android开发Jetpack组件Room使用讲解

    目录 简介 Room使用步骤 1 添加依赖 2 创建Entity实体类 3 声明Dao对象 4 声明Database对象 5 获取数据 6 最终使用 简介 Room 是 Google 官方推出的数据库 ORM 框架.ORM 是指 Object Relational Mapping,即对象关系映射,也就是将关系型数据库映射为面向对象的语言.使用 ORM 框架,我们就可以用面向对象的思想操作关系型数据库,不再需要编写 SQL 语句. Room使用步骤 1 添加依赖 build.gradle {app

  • 快速了解Android Room使用细则进阶

    目录 1.前言 2.@ForeignKey和@PrimaryKey 3.@TypeConverters 4.@Relation 5.@Transaction 6.@Embedded 7.@ColumnInfo (1)指定实体类中的字段名称 (2)指定实体类中的字段默认值 (3)指定实体类中的字段约束 8.@Ignore 忽略一个实体类中的字段 (1)忽略一个实体类中的 getter 和 setter 方法 (2)忽略一个实体类中的整个构造函数 9.@Index (1)在一个实体类中创建单个索引

  • 使用WEB工具快速提高Android开发效率

    正所谓工欲善其事,必先利其器.学习并应用优秀的轮子,可以让我们跑的更快,走的更远.这里所指的工具是广义的,泛指能帮助我们开发的东西,或者能提高我们效率的东西,包括:开发工具,监测工具,第三方代码库等. 在Google的广大支持下,便捷开发Android程序的Native工具层出不穷.其实Android开发涉及到的范围也不小,一些Web工具有时候也会带来事半功倍的效果.有些甚至是一些native应用无法做到的.本文,将简单列举一下本人正在使用的一些工具,当然也会持续更新. 查找优秀的参考工程 co

  • 快速解决android webview https图片不显示的问题

    Android webview 从Lollipop(5.0)开始webview默认不允许混合模式,https当中不能加载http资源,需要设置开启. 解决方法: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { webview.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); } 以上这篇快速解决android webview

  • 快速解决Android适配底部返回键等虚拟键盘的问题

    这个问题来来回回困扰了我很久,一直没能妥善解决. 场景1:华为手机遮挡了屏幕底部. 场景2:进入应用时,虚拟键自动缩回,留下空白区域. 需求: 需要安卓能自适应底部虚拟按键,用户隐藏虚拟按键时应用要占满整个屏幕,当用户启用虚拟键时,应用能往上收缩,等于是被底部虚拟按键顶上来. 需求很简单,实现起来却困难重重. 完美解决方案: 解释一下下面的代码,就是监听某个视图的变化,当可以看见的高度发生变化时,就对这个视图重新布局,保证视图不会被遮挡,也不会浪费屏幕空间.这一点尤其可用在像华为手机等可以隐藏和

  • 一分钟快速定位Android启动耗时问题

    目录 前言 1. 接入Tencent Matrix 2. 改造Application子类 3.运行,快速定位 总结 前言 Tencent Matrix默认无法监测Application冷启动的耗时方法,本文介绍了如何改造Matrix支持冷启动耗时方法监测.让你一分钟就能给App启动卡顿号脉. 1. 接入Tencent Matrix 1.1 在你项目根目录下的 gradle.properties 中配置要依赖的 Matrix 版本号,如: MATRIX_VERSION=1.0.0 1.2 在你项目

  • Android 多渠道打包进阶版

    目录 Android 多渠道打包进阶版 1.资源文件配置 2.依赖配置 3.签名配置 上一篇文章链接//www.jb51.net/article/221446.htm Android 多渠道打包进阶版 文章开始前,先看一下下面这种情况: android { productFlavors { //100 个多渠道配置 } //多渠道签名的配置 signingConfigs { xiaomi { storeFile file("../xiaomi.keystore") storePassw

  • 5分钟快速实现Android爆炸破碎酷炫动画特效的示例

    这个破碎动画,是一种类似小米系统删除应用时的爆炸破碎效果的动画. 效果图展示 先来看下是怎样的动效,要是感觉不是理想的学习目标,就跳过,避免浪费大家的时间.�� 源码在这里:point_right: https://github.com/ReadyShowShow/explosion 一行代码即可调用该动画 new ExplosionField(this).explode(view, null)) 下面开始我们酷炫的Android动画特效正式讲解:point_down: 先来个整体结构的把握 整

  • 快速解决Android平台移植ffmpeg的一些问题

    IT行业是一个踩在巨人肩膀上前进的行业,否则做的事情不一定有意义,所以我也是基于havlenapetr移植的ffmpeg基础上做了些改进,他做的主要贡献有: 1. 移植了ffmpeg并将与媒体相关的结构体在java层重新进行了封装,方便应用程序在java层直接操作ffmpeg API,如各种媒体格式转码及播放,如图1所示 2. 模仿Android的MediaPlayer类实现了ffmpeg的播放接口,如setDataSource(),setDisplay(),start(), stop(),pa

  • 快速掌握Android屏幕的知识点

    一.首先来介绍下关于PX.PT.PPI.DPI.DP的知识 术语 说明 PX (pixel),像素,屏幕上显示数据的最基本的点 PT (point), 点1pt=1/72英寸 PPI (pixel per inch),每英寸像素数 DPI (dot per inch),每英寸点数 DP 即dip(Density-independent pixel), 设备独立像素1dp=160dpi时1px长度 其中px, pt, dp为长度单位,ppi和dpi为密度单位 密度 ldpi  mdpi hdpi

  • 教你快速实现Android动态模糊效果

    前言 雅虎天气的界面上滑的时候背景图片会跟着移动,最重要的是背景图片会根据手指上下移动的距离来进行不同程度的模糊,感觉甚为惊奇,毕竟大家都知道,在Android平台上进行模糊渲染是一个相当耗CPU也相当耗时的操作,一旦处理不好,卡顿是在所难免的. 一般来说,考虑到效率,渲染一张图片最好的方法是使用OpenGL,其次是使用C++/C,使用Java代码是最慢的.但是Android推出RenderScript之后,我们就有了新的选择,测试表明,使用RenderScript的渲染效率和使用C/C++不相

随机推荐