ROOMの使い方の概要
| 順番 | 項目 | 説明 |
| 1 | 依存関係を追記 | ROOM自体を使えるようにする |
| 2 | テーブルを作成 | テーブル名、カラム設定など |
| 3 | DAOオブジェクトを作成 | テーブルの操作(SELECT、UPDATE、INSERT、DELETE文などを定義) |
| 4 | データベースクラスを作成 | RoomDatabaseを継承 |
| 5 | アクティビティでデータベースを扱う |
|
メモ:
通常データベースは、[DB作成] → [テーブル作成] の流れだが、内部で作成するので、
[テーブル作成] → [それをDBに入れ込む] という流れになる。
本来はViewModelを使用して将来の拡張性に備えるのが正しいと思いますが、今回は最小構成で行きます。
ROOMの使い方の例
今回の例では下図のアプリを作成します。
| レイアウト | 実際の画面 |
|
|
メモ:
今回の例では、氏名の入力ボックスを用意し、[追加] ボタンでROOMにデータを追加して、ListViewに一覧表示します。
[全消去] ボタンでデータをすべて消去します。
※コードを最小化するために、細かなエラー処理などは省略しています。
依存関係を追記する
build.gradle.kts(プロジェクト)に追記:
id("com.google.devtools.ksp") version "1.9.23-1.0.19" apply false
build.gradle.kts(アプリ)のpluginsの末尾に追記:
id("com.google.devtools.ksp")
build.gradle.kts(アプリ)のdependenciesに追記:
implementation("androidx.room:room-runtime:2.6.1")
implementation("androidx.room:room-ktx:2.6.1")
ksp("androidx.room:room-compiler:2.6.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
※エミュレーターがエラーになる場合
build.gradle.kts(アプリ)のandroidセクションの末尾に追記:
composeOptions{
kotlinCompilerExtensionVersion="1.5.11"
}
メモ:
ksp関連はアノテーション解析を可能にするため。
andriod.lifecycle…はコルーチンを使用するため。
テーブルを作成
右クリックで新しいクラスを作成する。この例では[myDataTable]としています。
@Entity(tableName="myContactList")
data class myDataTable(
@PrimaryKey(autoGenerate = true) val id: Int,
val firstName: String,
val lastName: String
)
DAOオブジェクトを作成
右クリックでInterfaceを選択して新しいクラスを作成する。この例では[myDao]としています。
@Dao
interface myDao {
//行挿入
@Insert
suspend fun insertAll(vararg users: myDataTable)
@Update
suspend fun updateDataTable(vararg users: myDataTable)
//全削除
@Query("DELETE FROM myContactList")
suspend fun deleteAll()
//全選択
@Query("SELECT * FROM myContactList")
suspend fun getAll(): List<myDataTable>
//IDをActivityで指定
@Query("SELECT * FROM myContactList WHERE id = :inputName")
suspend fun findByName(inputName: String): List<myDataTable>
}
データベースクラスを作成
右クリックで新しいクラスを作成する。この例では[myDatabase]としています。
@Database(entities = [myDataTable::class], version = 1, exportSchema = false)
public abstract class myDatabase: RoomDatabase() {
abstract fun myDao(): myDao
companion object{
@Volatile
private var INSTANCE: myDatabase ?= null
fun getDatabase(context: Context):myDatabase{
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(context.applicationContext,
klass = myDatabase::class.java, name = "datafile.db")
.build()
INSTANCE = instance
instance
}
}
}
}
アクティビティでデータベースを扱う
class MainActivity : AppCompatActivity() {
//アクティビティ全体でアクセスできるように初期化を遅延して宣言
private lateinit var database:myDatabase
private lateinit var myDao:myDao
private lateinit var adapter: ArrayAdapter<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//ここで初期化
database= myDatabase.getDatabase(this)
myDao = database.myDao()
//構成部品IDの取得
val etFirstName: EditText = findViewById(R.id.etFirstName)
val etLastName: EditText = findViewById(R.id.etLastName)
val btnAdd:Button = findViewById(R.id.btnAdd)
val btnShow:Button = findViewById(R.id.btnShow)
val btnDelete:Button = findViewById(R.id.btnDelete)
//テキストビューに値を表示する場合
val tvTable: TextView =findViewById(R.id.tvTable)
//リストビューに値を表示する場合
val lvTable: ListView = findViewById(R.id.lvTable)
adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, mutableListOf<String>())
lvTable.adapter = adapter
//追加ボタン
btnAdd.setOnClickListener {
lifecycleScope.launch{
withContext(Dispatchers.IO){
val add_user = myDataTable(0,etFirstName.text.toString(),etLastName.text.toString())
myDao.insertAll(add_user)
}
withContext(Dispatchers.Main){
//表示関数呼び出し
refreshText()
}
}
}
//削除ボタン
btnDelete.setOnClickListener {
lifecycleScope.launch{
withContext(Dispatchers.IO){
val allData=database.myDao().deleteAll()
}
withContext(Dispatchers.Main){
//表示関数呼び出し
refreshText()
}
}
}
}
//画面起動時にデータ取得
override fun onStart(){
super.onStart()
refreshText()
}
//再表示関数
fun refreshText() {
lifecycleScope.launch {
val allData = withContext(Dispatchers.IO) {
database.myDao().getAll()
}
val text = allData.map{ it.id.toString() + ", " + it.firstName + ", " + it.lastName }
adapter.clear()
adapter.addAll(text)
adapter.notifyDataSetChanged()
}
}
メモ:
データベース操作のDAOはコルーチン内でしか呼び出せないことに注意が必要。
関数refreshTextの処理内容もコルーチン化しているが、そもそも呼び出し元のボタン押下時の処理がコルーチン内で行われているため
コルーチン化しなくても良いが、onStartで呼び出しているからとりあえずそうしています。