iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0
Mobile Development

從零開始學習 Jetpack Compose系列 第 28

從零開始學習 Jetpack Compose Day27 - 專案實作(5)Room建立

  • 分享至 

  • xImage
  •  

今天主要會建立Room來做資料串接。

Room

Room 是 Android 的資料庫 Library,為 SQLite 提供抽象層,讓開發者更輕鬆、安全地使用資料庫。它簡化了資料庫操作,並支援編譯期檢查與異步查詢,避免繁瑣的 SQL 撰寫。

Room 主要有三個元件
。Entity:定義資料表結構。
。DAO (Data Access Object):操作資料表的方法。
。Database:連接資料庫的入口,使用 Room.databaseBuilder 建立。

要在 Compose 裡面使用 Room 首先要新增依賴

libs.version.toml

roomVersion = "2.6.1"
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "roomVersion"}
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "roomVersion"}
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "roomVersion"}

Project build.gradle.kts

plugins {
	   .
	   .
    id("com.google.devtools.ksp") version "1.9.0-1.0.12" apply false
}

app build.gradle.kts

plugins {
		.
		.
    id("com.google.devtools.ksp")
}

dependencies {
		.
	  implementation(libs.androidx.room.runtime)
    annotationProcessor(libs.androidx.room.compiler)
    implementation(libs.androidx.room.ktx)
    ksp(libs.androidx.room.compiler)
		.
		.
}

Entity

主要是定義資料表結構,我們這邊訂一個一個 TableName 叫 subscription,然後他有四個欄位分別是Id、productName、price、cycle。

@Entity(tableName = "subscription")
data class SubscriptionEntity(
    @PrimaryKey
    val id: Int,
    @ColumnInfo(name = "product_name")
    val productName: String,
    @ColumnInfo(name = "price")
    val price: String,
    @ColumnInfo(name = "cycle")
    val cycle: String
)

https://raw.githubusercontent.com/jian-fu-hung/ithelp-2024/refs/heads/main/Images/Day27/%E6%88%AA%E5%9C%96%202024-10-12%20%E6%99%9A%E4%B8%8A10.34.09.png

DAO

DAO 用來定義資料庫操作方法,透過註解如 @Insert@Update@Query@Delete 簡化資料存取邏輯。以下範例中,我們設計三個方法:

  1. getAll:用於查詢資料庫中的完整資料列表。
  2. setData:將新資料插入資料庫。
  3. updateData:更新已存在的資料內容。
@Dao
interface SubscriptionDao {
    @Query("SELECT * FROM subscription")
    suspend fun getAll(): List<SubscriptionEntity>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun setData(item: SubscriptionEntity)

    @Update
    suspend fun updateData(item: SubscriptionEntity)
}

Database

Database 是用來定義資料庫的主要入口,負責建立和管理資料表以及版本控制。它會包含所有對應的 DAO 介面,讓我們透過它們來進行資料存取操作。以下的範例中我們定義了一個subscriptionDao方法它提供SubscriptionDao介面來讓我們操作。

@Database(entities = [SubscriptionEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun subscriptionDao(): SubscriptionDao
}

資料源調整

上面我們把 Room 建好後接下來我們要調整我們的AppDataManagerImpl

首先我們要先建立Database

private var dbManager: AppDatabase = Room.databaseBuilder(context, AppDatabase::class.java, "database.db").build()

把每個方法串接我們定義的DAO

class AppDataManagerImpl(context: Application) : AppDataManager {

    var list = mutableListOf<SubscriptionViewData>()

    private var dbManager: AppDatabase = Room.databaseBuilder(context, AppDatabase::class.java, "database.db").build()

    override suspend fun getData(): List<SubscriptionViewData> {
        val dataList = dbManager.subscriptionDao().getAll()
        list = dataList.map {
            SubscriptionViewData(
                id = it.id.toString(),
                name = it.productName,
                price = it.price,
                cycle = it.cycle
            )
        }.toMutableList()
        return list
    }

    override suspend fun setData(data: SubscriptionViewData) {
        val item = SubscriptionEntity(
            id = list.size,
            productName = data.name,
            price = data.price,
            cycle = data.cycle
        )

        dbManager.subscriptionDao().setData(item)
    }

    override suspend fun updateData(data: SubscriptionViewData) {
        list.find { it.id == data.id }?.let {
            val item = SubscriptionEntity(
                id = it.id.toInt(),
                productName = data.name,
                price = data.price,
                cycle = data.cycle
            )
            dbManager.subscriptionDao().updateData(item)
        }
    }
}

接著我們去AppApplication中調整資料源,把原先的 AppDataManagerMock 改成 AppDataManagerImpl

class AppApplication : Application() {

    private lateinit var appDataManager: AppDataManager

    override fun onCreate() {
        super.onCreate()
        appDataManager = AppDataManagerImpl(this)
    }


    fun getAppDataManager() = appDataManager
}

主畫面調整

在測試時發現回到首頁資料不會進行,因此補上LaunchedEffect 當進入畫面時更新資料,或許 ViewModel 跟 AppDataManager 之間改用 StateFlow 也可以解決,但目前還沒想到作法,因此就先這樣調整。

    LaunchedEffect(Unit) {
        viewModel.reload()
    }

畫面呈現

初始畫面
https://raw.githubusercontent.com/jian-fu-hung/ithelp-2024/refs/heads/main/Images/Day27/%E6%88%AA%E5%9C%96%202024-10-12%20%E6%99%9A%E4%B8%8A11.00.14.png

接著我們新增資料
https://raw.githubusercontent.com/jian-fu-hung/ithelp-2024/refs/heads/main/Images/Day27/%E6%88%AA%E5%9C%96%202024-10-12%20%E6%99%9A%E4%B8%8A11.00.34.png
https://raw.githubusercontent.com/jian-fu-hung/ithelp-2024/refs/heads/main/Images/Day27/%E6%88%AA%E5%9C%96%202024-10-12%20%E6%99%9A%E4%B8%8A11.00.43.png

再來我們編輯資料
https://raw.githubusercontent.com/jian-fu-hung/ithelp-2024/refs/heads/main/Images/Day27/%E6%88%AA%E5%9C%96%202024-10-12%20%E6%99%9A%E4%B8%8A11.00.58.png
https://raw.githubusercontent.com/jian-fu-hung/ithelp-2024/refs/heads/main/Images/Day27/%E6%88%AA%E5%9C%96%202024-10-12%20%E6%99%9A%E4%B8%8A11.01.08.png

以上為今天的內容。


上一篇
從零開始學習 Jetpack Compose Day26 - 詳細頁ViewModel建立
下一篇
從零開始學習 Jetpack Compose Day28 - Compose UI Test
系列文
從零開始學習 Jetpack Compose30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言