RoomによるローカルDBの実装
先週某社の採用フローにエントリしたところ、1週間で簡易的な Todo アプリ作成の課題を与えられました。
その際、初めて Room を使用しローカルDBを構築、さらに ViewModel に埋め込んで連携したので、備忘的にメモしておきます。
Room とは
SQLite データベースへのアクセスに便利な抽象化レイヤーを提供するライブラリです。 Android Architecture Components のライブラリ群の一つとして Google I/O 2017 で公開されました。
実装のステップ
おおむね次の順番で実装を行うとスムーズかもしれません。
- Entity の作成
- Data Access Object(Dao)の作成
- Database の作成
- DataSource インターフェースの定義
- Database の利用
導入したライブラリ
implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" // optional - Kotlin Extensions and Coroutines support for Room implementation "androidx.room:room-ktx:$room_version"
Room の実装
次のような Todo リスト用のテーブルをもった DB を作ってみます。
id | taskName | isCompleted |
---|---|---|
1 | hoge | Active |
2 | fuga | Completed |
Entity の作成
@Entity
アノテーションを付与した data class を作成します。
これが上記のテーブルにあたります。
@Entity(tableName = "tasks") data class Task( @PrimaryKey(autoGenerate = true) val id: Long, val name: String, val isCompleted: String )
id
を主キーとして@PrimaryKey
を付与しています。
autoGenerate = true
とすることで勝手に値を振ってくれますが、レコードを追加するときにid = 0
またはid = null
を指定する必要があるのでご注意を。
PrimaryKey | Android Developers
Data Access Object(Dao)の作成
@Dao
アノテーションを付与したインターフェースを定義します。
@Dao interface TasksDao { @Query("SELECT * FROM tasks WHERE name LIKE :taskName") fun find(taskName: String): List<Task> @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(task: Task) @Update fun update(task: Task): Int @Delete fun delete(task: Task): Int }
データにアクセスするためのメソッドを定義し、そのメソッドの呼び出しにより実行するクエリを記述します。 付与できるアノテーションは次の4つです。
@Query
@Insert
@Update
@Delete
@Insert
, @Update
, @Delete
では引数で Task オブジェクトを渡してやることにより、データの修正や追加、削除を実行します。
@Query
では SELECT 文を記述することで自由にクエリを実行できます。
Database の作成
@Database
アノテーションを付与した抽象クラスを作成します。
このとき、抽象クラスは RoomDatabase
を継承したクラスとします。
Room.databaseBuilder
によりデータベースを生成します。
@Database(entities = [Task::class], version = 1, exportSchema = false) abstract class TasksLocalDatabase : RoomDatabase() { abstract fun tasksDao(): TasksDao companion object { private var INSTANCE: TasksLocalDatabase? = null private val lock = Any() fun getInstance(context: Context): TasksLocalDatabase = INSTANCE ?: synchronized(lock) { INSTANCE ?: Room.databaseBuilder( context.applicationContext, TasksLocalDatabase::class.java, "Tasks.db" ) .build() .also { INSTANCE = it } } fun destroyInstance() { INSTANCE = null } } }
companion object
によりシングルトンなオブジェクトとして定義しましょう。
Database の利用
最後に Room で構築した DB の利用です。
val localDatabase = TasksLocalDatabase.getInstance(context) val dao = localDatabase.tasksDao() // Dao のメソッドをコールすることにより DB の操作を実行 val tasks = dao.find("hoge") dao.insert(newTask) dao.delete(delTask) ...
アプリに MVVM を採用している場合は、ViewModelFactory で ViewModel を生成するときにデータベースを埋め込んでしまった方が便利でしょう。
おわりに
なお某社は落ちました(ぇ
これで転職活動は振り出しに……( ^ω^)