Android_studio:TOP

ROOMを使う

ROOMの使い方の概要


順番項目説明
1依存関係を追記ROOM自体を使えるようにする
2テーブルを作成テーブル名、カラム設定など
3DAOオブジェクトを作成テーブルの操作(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で呼び出しているからとりあえずそうしています。