Room 简单使用

创建 item 实体

Entity 类定义了一个表,该类的每个实例都表示数据库表中的一行。Entity 类以映射告知 Room 它打算如何呈现数据库中的信息并与之交互。在此应用中,实体将保存有关商品目录商品的信息,例如商品名称、商品价格和商品数量。

@Entity 注解用于将某个类标记为数据库 Entity 类。对于每个 Entity 类,该应用都会创建一个数据库表来保存这些项。除非另行说明,否则 Entity 的每个字段在数据库中都表示为一列。存储在数据库中的每个实体实例都必须有一个主键。主键用于唯一标识数据库表中的每个记录/条目。应用分配主键后,便无法再修改主键;只要主键存在于数据库中,它就会表示实体对象。

在此任务中,将创建一个 Entity 类,并定义字段来存储每个商品的以下商品目录信息:Int 用于存储主键,String 用于存储商品名称,double 用于存储商品价格,Int 用于存储库存数量。

kotlin 复制代码
@Entity(tableName = "items")
data class Item(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    val name: String,
    val price: Double,
    val quantity: Int
)

创建 item DAO

数据访问对象 (DAO) 是一种模式(单一责任原则),其作用是通过提供抽象接口将持久性层与应用的其余部分分离,负责定义用于访问数据库的接口。

DAO 的功能在于,让在底层持久性层执行数据库操作所涉及的所有复杂性与应用的其余部分分离。这样,就可以独立于使用数据的代码更改数据层。

Room 库提供了便捷注解(例如 @Insert@Delete@Update),用于定义执行简单插入、删除和更新的方法,而无需编写 SQL 语句。如果需要定义更复杂的插入、删除或更新操作,或者需要查询数据库中的数据,请改用 @Query 注解。

数据库操作的执行可能用时较长,因此需要在单独的线程上运行。Room 不允许在主线程上访问数据库。

kotlin 复制代码
import androidx.room.Dao

@Dao
interface ItemDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insert(item: Item)

    @Update
    suspend fun update(item: Item)

    @Delete
    suspend fun delete(item: Item)

    @Query("SELECT * from items WHERE id = :id")
    fun getItem(id: Int): Flow<Item>

    @Query("SELECT * from items ORDER BY name ASC")
    fun getAllItems(): Flow<List<Item>>
}

添加参数 onConflict 并为其赋值 OnConflictStrategy.``IGNORE。参数 onConflict 用于告知 Room 在发生冲突时应该执行的操作。OnConflictStrategy.``IGNORE 策略会忽略新商品。

由于返回值类型为 Flow,Room 还会在后台线程上运行该查询。无需将其明确设为 suspend 函数并在协程作用域内调用它。

创建 Database 实例

Database 类可为应用提供定义的 DAO 实例。反过来,应用可以使用 DAO 从数据库中检索数据,作为关联的数据实体对象的实例。此外,应用还可以使用定义的数据实体更新相应表中的行,或者创建新行供插入。

需要创建一个抽象 RoomDatabase 类,并为其添加 @Database 注解。此类有一个方法,如果数据库不存在,该方法会返回 RoomDatabase 的现有实例。

获取 **RoomDatabase** 实例的一般过程:

  1. 创建一个扩展 RoomDatabasepublic abstract 类。您定义的新抽象类将用作数据库持有者。您定义的类是抽象类,因为 Room 会为您创建实现。
  2. 为该类添加 @Database 注解。在参数中,为数据库列出实体并设置版本号。
  3. 定义一个返回 ItemDao 实例的抽象方法或属性,Room 会为您生成实现。
  4. 整个应用只需要一个 RoomDatabase 实例,因此请将 RoomDatabase 设为单例。
  5. 使用 RoomRoom.databaseBuilder 创建 (item_database) 数据库。不过,仅当该数据库不存在时才应创建。否则,请返回现有数据库。
kotlin 复制代码
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

/**
* Database class with a singleton Instance object.
*/
@Database(entities = [Item::class], version = 1, exportSchema = false)
abstract class InventoryDatabase : RoomDatabase() {

    abstract fun itemDao(): ItemDao

    companion object {
        @Volatile
        private var Instance: InventoryDatabase? = null

        fun getDatabase(context: Context): InventoryDatabase {
            // if the Instance is not null, return it, otherwise create a new database instance.
            return Instance ?: synchronized(this) {
                Room.databaseBuilder(context, InventoryDatabase::class.java, "item_database")
                    .build()
                    .also { Instance = it }
            }
        }
    }
}

exportSchema 设为 false,这样就不会保留架构版本记录的备份。

volatile 变量的值绝不会缓存,所有读写操作都将在主内存中完成。这些功能有助于确保 Instance 的值始终是最新的,并且对所有执行线程都相同。也就是说,一个线程对 Instance 所做的更改会立即对所有其他线程可见。

实现存储库

将实现 ItemsRepository 接口和 OfflineItemsRepository 类,以从数据库提供 getinsertdeleteupdate 实体。

kotlin 复制代码
import kotlinx.coroutines.flow.Flow

/**
* Repository that provides insert, update, delete, and retrieve of [Item] from a given data source.
*/
interface ItemsRepository {
    /**
     * Retrieve all the items from the the given data source.
     */
    fun getAllItemsStream(): Flow<List<Item>>

    /**
     * Retrieve an item from the given data source that matches with the [id].
     */
    fun getItemStream(id: Int): Flow<Item?>

    /**
     * Insert item in the data source
     */
    suspend fun insertItem(item: Item)

    /**
     * Delete item from the data source
     */
    suspend fun deleteItem(item: Item)

    /**
     * Update item in the data source
     */
    suspend fun updateItem(item: Item)
}
kotlin 复制代码
import kotlinx.coroutines.flow.Flow

class OfflineItemsRepository(private val itemDao: ItemDao) : ItemsRepository {
    override fun getAllItemsStream(): Flow<List<Item>> = itemDao.getAllItems()

    override fun getItemStream(id: Int): Flow<Item?> = itemDao.getItem(id)

    override suspend fun insertItem(item: Item) = itemDao.insert(item)

    override suspend fun deleteItem(item: Item) = itemDao.delete(item)

    override suspend fun updateItem(item: Item) = itemDao.update(item)
}

实现 AppContainer 类

kotlin 复制代码
override val itemsRepository: ItemsRepository by lazy {
    OfflineItemsRepository(InventoryDatabase.getDatabase(context).itemDao())
}
相关推荐
阿巴斯甜2 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker2 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95272 天前
Andorid Google 登录接入文档
android
黄林晴2 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇2 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_3 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android