Jetpack

【Jetpack】Android Room 資料庫 範例

【Jetpack】Android Room 資料庫 範例

Android Room 是 Android 開發中的一個持久性庫,用於與 SQLite 數據庫進行交互。它是 Google 官方推薦的一種數據庫解決方案,旨在簡化數據庫操作的開發流程。

Room 提供了一個對象關係映射(Object-Relational Mapping,ORM)的抽象層,允許開發者使用面向對象的方式來訪問和操作數據庫。它將Java對象映射到數據庫表格,並提供了方便的 API 來執行常見的 CRUD 操作(創建、讀取、更新、刪除)。此外,Room還支持數據庫事務、查詢優化和異步操作等功能。

Room 的主要組件包括實體(Entity)、數據訪問對象(Data Access Object,DAO)和數據庫(Database)。開發者需要定義實體類來表示數據庫中的表格,使用 DAO 類定義數據庫操作的方法,並創建數據庫類來定義數據庫的配置和版本管理。

使用 Room 可以大大簡化 Android 應用程序中數據庫操作的編寫工作,提高代碼的可讀性和維護性。它還提供了內建的編譯時檢查和錯誤提示,幫助開發者減少常見的錯誤和提高開發效率。


文章目錄

  1. Room 導入
  2. Room 創建 Table
  3. Room 創建 Dao
  4. Room 創建 Database
  5. Room 用法
  6. Developer Documents Room

1.Room 導入

build.gradle(Module :app)
plugins {
    id 'kotlin-kapt'
}

dependencies {
    // room
    implementation 'androidx.room:room-runtime:2.5.2'
    implementation "androidx.room:room-ktx:2.5.2"
    kapt 'androidx.room:room-compiler:2.5.2'

    // lifecycle
    implementation "androidx.fragment:fragment-ktx:1.6.0"
}

2.Room 創建 Table

NotificationEntity.kt
@Entity(tableName = "notification")
data class NotificationEntity(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    val sender: String,
    val body: String,
    val dateTime: String,
    val uuid: String,
    val upload: Boolean
)

3.Room 創建 Dao

NotificationDao.kt
@Dao
interface NotificationDao {

    @Insert
    suspend fun insert(vararg notifications: NotificationEntity)

    @Query("DELETE FROM notification")
    suspend fun deleteAll()

    @Query("SELECT * FROM notification")
    fun getNotifications(): Flow<List<NotificationEntity>>

}

4.Room 創建 Database

NotificationDatabase.kt
@Database(entities = [NotificationEntity::class], version = 1)
abstract class NotificationDatabase : RoomDatabase() {

    abstract fun notificationDao(): NotificationDAO

    companion object {

        @Volatile
        private var INSTANCE: NotificationDatabase? = null

        fun getDatabase(context: Context): NotificationDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context,
                    NotificationDatabase::class.java,
                    "NotificationDatabase"
                ).build()
                INSTANCE = instance
                instance
            }
        }

    }
}

5.Room 用法

NotificationViewModel.kt
class NotificationViewModel(application: Application) : AndroidViewModel(application) {

    private val database = NotificationDatabase.getDatabase(application)

    val notifications = database.notificationDao().getNotifications()

    fun insert(vararg notifications: NotificationEntity) = viewModelScope.launch {
        database.notificationDao().insert(*notifications)
    }

    fun deleteAll() = viewModelScope.launch {
        database.notificationDao().deleteAll()
    }

}

class NotificationViewModelFactory(private val application: Application) :
    ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(NotificationViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return NotificationViewModel(application) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}
NotificationListAdapter.kt
class NotificationListAdapter: ListAdapter<NotificationEntity, RecyclerView.ViewHolder>(DiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return NotificationViewHolder.create(parent)
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val notification = getItem(position)
        when (holder) {
            is NotificationViewHolder -> {
                holder.bind(notification.id.toString())
            }
        }
    }

    class NotificationViewHolder(private val binding: RecyclerviewItemBinding) : RecyclerView.ViewHolder(binding.root) {

        fun bind(text: String) {
            binding.textView.text = text
        }

        companion object {
            fun create(parent: ViewGroup): NotificationViewHolder {
                val binding = RecyclerviewItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
                return NotificationViewHolder(binding)
            }
        }
    }

    class DiffCallback : DiffUtil.ItemCallback<NotificationEntity>() {
        override fun areItemsTheSame(oldItem: NotificationEntity, newItem: NotificationEntity): Boolean {
            return oldItem == newItem
        }

        override fun areContentsTheSame(oldItem: NotificationEntity, newItem: NotificationEntity): Boolean {
            return oldItem == newItem
        }
    }

}
MainActivity.kt
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private val notificationViewModel: NotificationViewModel by viewModels {
        NotificationViewModelFactory(application)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        lifecycleScope.launch {
            notificationViewModel.deleteAll()
        }

        binding.add.setOnClickListener {
            lifecycleScope.launch {
                notificationViewModel.insert(
                    NotificationEntity(sender = "Father", body = "Hello", dateTime = Instant.ofEpochMilli(System.currentTimeMillis()).toString(), uuid = "AA", upload = false),
                    NotificationEntity(sender = "Mother", body = "Good Morning", dateTime = Instant.ofEpochMilli(System.currentTimeMillis()).toString(), uuid = "BB", upload = false)
                )

                withContext(Dispatchers.Main) {
                    Toast.makeText(this@MainActivity, "Insert success", Toast.LENGTH_SHORT).show()
                }
            }
        }

        binding.recyclerview.apply {
            val notificationAdapter = NotificationListAdapter()
            adapter = notificationAdapter
            layoutManager = LinearLayoutManager(this@MainActivity)
            setHasFixedSize(true)

            lifecycleScope.launch {
                notificationViewModel.notifications.collect { notifications ->
                    notificationAdapter.submitList(notifications)
                }
            }
        }
    }
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/add"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@drawable/add"
        android:contentDescription="add" />

</androidx.constraintlayout.widget.ConstraintLayout>
recyclerview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/textView"
        style="@style/word_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_orange_light" />

</LinearLayout>

6.Developer Documents Room

Open in Documents ViewModel

發表迴響