
みなさまこんにちは〜!
メモリアインクのすだです。
本日は、KotlinにおけるRoomを使ったローカルデータベースの扱い方について解説していきます。
この記事を読んでわかること…
・Roomとは
・Roomの導入方法
・Roomの使い方
環境
- Kotlin (ver 1.9.0)
- Android Studio (Giraffe | 2022.3.1 Patch 3)
Roomとは?
Room は、Android公式のローカルデータベースライブラリです。
SQLite(軽量なデータベース)を Kotlin や Java から簡単・安全に使えるようにラップしたものです。
https://developer.android.com/codelabs/basic-android-kotlin-compose-persisting-data-room?hl=ja#0
Roomの仕様には、以下のような特徴があります。:
①型安全
Roomでは、データ型(Int、Stringなど)をKotlin側で指定できるため、
コンパイル時(アプリをビルドするとき)にミスを早めに発見できます。また、SQLのクエリ文に書いた カラム名のミスや、構文エラーもチェックしてくれるので、
「実行してからクラッシュに気づく」という失敗が起きにくくなります。
②アノテーションの利用
Roomでは、@Entity
や @Dao
などのアノテーションを使うだけで、テーブルやデータ操作を簡単に定義できます。SQLをたくさん書かなくても、少ないコードでデータベースを作って使えるのが大きな特徴です。
Roomの導入
Room ライブラリを Gradle に追加します。build.gradle(:app)
に以下を追加してください。▼
dependencies {
// Room本体
implementation "androidx.room:room-runtime:2.6.1"
// Kotlin用の拡張機能(Coroutinesなどを使うなら必須)
implementation "androidx.room:room-ktx:2.6.1"
// アノテーション処理(Roomが内部でコードを自動生成するために必要)
kapt "androidx.room:room-compiler:2.6.1"
}
(Kotlinを使っている場合は kapt
を使います)
もしまだなら、kapt
プラグインも追加してください。▼
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt' // ← これを追加
}
kapt
(Kotlin Annotation Processing Tool)とは、Kotlinで「@~」というアノテーションを使って、自動的にコードを生成する仕組みです。
Room実装の全体フロー
Roomを使うには、大きく以下の3つのクラスが必要です:
- Entity(エンティティ):データベースに保存する1行分のデータの設計図
- DAO(Data Access Object):データ操作を行うインターフェース
- Databaseクラス:Room全体をまとめる役割の抽象クラス
イメージ図としては以下のような感じです。
User(@Entity) → テーブル定義
↓
UserDao(@Dao) → データの出し入れ
↓
AppDatabase(@Database) → Roomのデータベース本体
早速、実装しながら理解していきましょう。↓
Room実装ステップ
Entityを作成
@Entity
data class User(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val name: String,
val mailAdress: String
)
上記の Userクラスは、Roomでいうところの「テーブル」にあたります。
Kotlin の data class
に @Entity
アノテーションを付けることで、データベースのテーブルとして扱うことができます。
主キー(Primary Key)には、@PrimaryKey
アノテーションを付けましょう。
また、autoGenerate = true
を指定すると、主キー(ID)を自動で連番で割り振ってくれるようになります。
自動採番したい場合は、このオプションを追加するのがおすすめです。
DAO(データアクセスオブジェクト)を定義
@Dao
interface UserDao {
@Insert
suspend fun insert(user: User)
@Query("SELECT * FROM User ORDER BY id DESC")
suspend fun getAll(): List<User>
}
Roomでは、データベースへの挿入・取得・更新・削除などの操作を、
DAO(Data Access Object)というインターフェースにまとめて記述します。
このインターフェースには、@Dao
アノテーションを付けて、Room用のデータアクセスクラスであることを明示します。
@Insert
は、データベースに 1件のデータを追加するためのアノテーションです。
この関数に渡された User オブジェクトの情報は、Userテーブルの1行分のデータとして保存されます。
主キーに autoGenerate = true
を指定している場合は、IDが自動的に連番で割り振られます。
また、関数に suspend
を付けることで、コルーチンを使った非同期処理として安全に呼び出すことができるようになります。
@Query
アノテーションを使うと、SQL文を直接記述してデータを操作できます。
たとえば、データの一覧取得や条件検索、並び替えなどを柔軟に行うことができます。
Databaseクラスを定義
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
このクラスは、Room全体の中核を担う「データベース本体」です。
Roomを使ううえで必要な、エンティティ(テーブル)と DAO を紐づける役割を担います。
@Database
アノテーションをつけて、中に内容を書きます。▼
entities = [User::class]
:
Userというdata classが1つのテーブルになるという意味です。複数ある場合はカンマ区切りで追加できます。
version = 1
:
データベースのバージョン番号です。テーブル構造を変更したいとき(カラム追加・削除など)に、バージョン番号を上げてマイグレーション処理を行うために使います。
abstract class AppDatabase : RoomDatabase()
は
Roomを使うために必要な、抽象クラスです。
Roomが内部的にこのクラスを継承して、データベースの機能を自動生成してくれます。
このクラスは RoomDatabase を継承した抽象クラス(abstract class) である必要があります。
名前は自由ですが、一般的には AppDatabase
、MyDatabase
などがよく使われます。
そしてabstract fun userDao(): UserDao
は
このデータベースが提供する DAO(データ操作窓口)を定義しています。
ここで定義した関数名は自由です(ただし戻り値の型は DAO インターフェースにする)
呼び出し側からは、Room.databaseBuilder()
を使ってインスタンスを作成したあとに、ここから DAO を取得します。▼
val db = Room.databaseBuilder(context, AppDatabase::class.java, "my_db").build()
val dao = db.breakfastDao()
呼び出し側の実装例
Roomを使ってDBを定義できたところで、
このDBを呼び出して操作する実装例をご紹介します。
例:Repositoryから呼び出す
class UserRepository(private val dao: UserDao) {
suspend fun add(name: String, mailAdress: String) {
val user = User(name = name, mailAdress = mailAdress)
dao.insert(user)
}
suspend fun getAll(): List<User> = dao.getAll()
}
User
エンティティのオブジェクトを生成し、
それを UserDao
の insert()
関数に渡すことで、ユーザー情報を新規作成(追加)する処理が実行されます。
このとき、User
オブジェクトには名前やメールアドレスなどの情報がセットされており、
その内容に基づいて、データベースの User
テーブルに1行分のデータが追加されます。
getAllも同様に、UserDaoの処理を呼び出してユーザー情報を取得する内容になっています。
Roomデータベースの初期化
そしてさらに、UserRepository の処理を呼び出すには、引数として UserDao
のインスタンスが必要です。
そのためには、Roomデータベースを初期化しておく必要があります。
以下は、Roomのデータベースを構築(インスタンス化)し、Repository に渡す処理の例です。
// 初期化(RoomとRepositoryをつなぐ)
val db = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java,
"user-db"
).build()
val repository = UserRepository(db.userDao())
このコードでは、Room.databaseBuilder
を使って、Roomのデータベースインスタンスを作成しています。
・applicationContext
… アプリ全体で共有できるコンテキスト。データベースはアプリ全体で1つなのでこれを使うのが基本です。
・AppDatabase::class.java
… @Database
アノテーションをつけたデータベース本体のクラス
・"user-db"
… データベースのファイル名(スマホ内に user-db
という名前で保存される)
.build()
を呼び出すことで、実際のデータベースオブジェクト(AppDatabase
)が作られます。
そして、db.userDao()
でAppDatabase
クラスの中にある abstract fun userDao(): UserDao
を呼び出すことで、Roomが自動で用意してくれた UserDao
の実装インスタンスを取得しています。
まとめ
おつかれさまでした。いかがでしたでしょうか!
Roomは、@Entity
・@Dao
・@Database
の3点セットで構築できるのが大きな特徴です。
アプリにおけるデータの永続化(保存・管理)を実装したい場合、Roomは非常に便利な選択肢となります。
ぜひ、技術選定のひとつとして検討してみてください。



技術者としてのキャリアパスを次のレベルへと進めたい皆様、
<未経験からIT・Webエンジニアを目指すなら【ユニゾンキャリア】>
自分の市場価値をさらに向上させてみませんか?
それではまた次回の記事でお会いしましょう!
コメント