【正社員】還元率83%【フリーランス】マージン一律5万円で案件をご紹介させていただきます。 詳細はこちら

【Android】<Kotlin>Roomで作るローカルDB入門|導入〜実装までわかりやすく解説

【Android】<Kotlin>Roomで作るローカルDB入門|導入〜実装までわかりやすく解説
すだ

みなさまこんにちは〜!
メモリアインクのすだです。

本日は、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つのクラスが必要です:

  1. Entity(エンティティ):データベースに保存する1行分のデータの設計図
  2. DAOData Access Object:データ操作を行うインターフェース
  3. 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) である必要があります。
名前は自由ですが、一般的には AppDatabaseMyDatabase などがよく使われます。

そして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 エンティティのオブジェクトを生成し、
それを UserDaoinsert() 関数に渡すことで、ユーザー情報を新規作成(追加)する処理が実行されます。

このとき、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エンジニアを目指すなら【ユニゾンキャリア】
を通じて、
自分の市場価値をさらに向上させてみませんか?

それではまた次回の記事でお会いしましょう!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

弊社テックブログをご愛読いただきありがとうございます。
当テックブログを運用している株式会社メモリアインクは、
【正社員】還元率83%
【フリーランス】マージン一律5万円で案件のご紹介
と、エンジニアの皆様に分かりやすい形で稼げる仕組みを構築し提供させていただいております。

コメント

コメントする

目次