Room を使用してローカル データベースにデータを保存する
Android Jetpack の一部。
コレクションでコンテンツを整理
必要に応じて、コンテンツの保存と分類を行います。
比較的大量の構造化データを処理するアプリは、そのデータをローカルに永続化することで大きなメリットを得ることができます。最も一般的なユースケースは、デバイスがネットワークにアクセスできない場合でも、ユーザーがオフラインの間にコンテンツをブラウジングできるように、関連するデータをキャッシュに保存することです。
Room 永続ライブラリは SQLite 全体に抽象化レイヤを提供することで、データベースへのスムーズなアクセスを可能にし、SQLite を最大限に活用できるようにします。特に、Room には次のようなメリットがあります。
- SQL クエリのコンパイル時検証。
- 繰り返しが多く間違いを犯しやすいボイラープレート コードを最小限に抑える便利なアノテーション。
- 効率的なデータベース移行パス。
こうしたことから、SQLite API を直接使用するのではなく、Room を使用することを強くおすすめします。
設定
アプリで Room を使用するには、アプリの build.gradle
ファイルに次の依存関係を追加します。
dependencies { val room_version = "2.7.0" implementation("androidx.room:room-runtime:$room_version") // If this project uses any Kotlin source, use Kotlin Symbol Processing (KSP) // See Add the KSP plugin to your project ksp("androidx.room:room-compiler:$room_version") // If this project only uses Java source, use the Java annotationProcessor // No additional plugins are necessary annotationProcessor("androidx.room:room-compiler:$room_version") // optional - Kotlin Extensions and Coroutines support for Room implementation("androidx.room:room-ktx:$room_version") // optional - RxJava2 support for Room implementation("androidx.room:room-rxjava2:$room_version") // optional - RxJava3 support for Room implementation("androidx.room:room-rxjava3:$room_version") // optional - Guava support for Room, including Optional and ListenableFuture implementation("androidx.room:room-guava:$room_version") // optional - Test helpers testImplementation("androidx.room:room-testing:$room_version") // optional - Paging 3 Integration implementation("androidx.room:room-paging:$room_version") }
dependencies { def room_version = "2.7.0" implementation "androidx.room:room-runtime:$room_version" // If this project uses any Kotlin source, use Kotlin Symbol Processing (KSP) // See KSP Quickstart to add KSP to your build ksp "androidx.room:room-compiler:$room_version" // If this project only uses Java source, use the Java annotationProcessor // No additional plugins are necessary annotationProcessor "androidx.room:room-compiler:$room_version" // optional - RxJava2 support for Room implementation "androidx.room:room-rxjava2:$room_version" // optional - RxJava3 support for Room implementation "androidx.room:room-rxjava3:$room_version" // optional - Guava support for Room, including Optional and ListenableFuture implementation "androidx.room:room-guava:$room_version" // optional - Test helpers testImplementation "androidx.room:room-testing:$room_version" // optional - Paging 3 Integration implementation "androidx.room:room-paging:$room_version" }
主要コンポーネント
Room は、次の 3 つの主要コンポーネントで構成されます。
- データベース クラス。データベースを保持し、アプリの永続データに対する基礎的な接続のメイン アクセス ポイントとして機能します。
- データ エンティティ。アプリのデータベースのテーブルを表します。
- データアクセス オブジェクト(DAO)。アプリがデータベースのデータのクエリ、更新、挿入、削除に使用できるメソッドを提供します。
データベース クラスは、そのデータベースに関連付けられている DAO のインスタンスをアプリに提供します。アプリはこの DAO を使用して、関連するデータ エンティティ オブジェクトのインスタンスとしてデータベースからデータを取得できます。また、定義されたデータ エンティティを使用して、対応するテーブルの行を更新したり、挿入用の新しい行を作成したりできます。図 1 に、Room のさまざまなコンポーネントの関係を示します。

実装例
このセクションでは、1 つのデータ エンティティと 1 つの DAO で Room データベースを実装する例を示します。
データ エンティティ
次のコードは、User
データ エンティティを定義しています。User
の各インスタンスは、アプリのデータベースにある user
テーブルの行を表します。
@Entity data class User( @PrimaryKey val uid: Int, @ColumnInfo(name = "first_name") val firstName: String?, @ColumnInfo(name = "last_name") val lastName: String? )
@Entity public class User { @PrimaryKey public int uid; @ColumnInfo(name = "first_name") public String firstName; @ColumnInfo(name = "last_name") public String lastName; }
Room のデータ エンティティの詳細については、Room エンティティを使用してデータを定義するをご覧ください。
データ アクセス オブジェクト(DAO)
次のコードは、UserDao
という DAO を定義しています。UserDao
は、user
テーブルのデータを操作するためにアプリの他の部分が使用するメソッドを提供します。
@Dao interface UserDao { @Query("SELECT * FROM user") fun getAll(): List<User> @Query("SELECT * FROM user WHERE uid IN (:userIds)") fun loadAllByIds(userIds: IntArray): List<User> @Query("SELECT * FROM user WHERE first_name LIKE :first AND " + "last_name LIKE :last LIMIT 1") fun findByName(first: String, last: String): User @Insert fun insertAll(vararg users: User) @Delete fun delete(user: User) }
@Dao public interface UserDao { @Query("SELECT * FROM user") List<User> getAll(); @Query("SELECT * FROM user WHERE uid IN (:userIds)") List<User> loadAllByIds(int[] userIds); @Query("SELECT * FROM user WHERE first_name LIKE :first AND " + "last_name LIKE :last LIMIT 1") User findByName(String first, String last); @Insert void insertAll(User... users); @Delete void delete(User user); }
DAO の詳細については、Room DAO を使用してデータにアクセスするをご覧ください。
データベース
次のコードは、データベースを保持するために AppDatabase
クラスを定義しています。AppDatabase
はデータベース構成を定義し、永続データに対するアプリのメイン アクセス ポイントとして機能します。データベース クラスは次の条件を満たす必要があります。
- クラスには、データベースに関連付けられたすべてのデータ エンティティをリストする
entities
配列を含む@Database
アノテーションを付ける必要があります。 - クラスは、
RoomDatabase
を拡張する抽象クラスである必要があります。 - データベースに関連付けられた DAO クラスごとに、引数ゼロで DAO クラスのインスタンスを返す抽象メソッドを定義する必要があります。
@Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao }
@Database(entities = {User.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); }
注: 単一のプロセスで動作するアプリの場合は、AppDatabase
オブジェクトをインスタンス化する際にシングルトン デザイン パターンに従う必要があります。各 RoomDatabase
インスタンスは非常に高コストであり、単一のプロセス内で複数のインスタンスにアクセスする必要はほとんどありません。
複数のプロセスで動作するアプリの場合は、データベース ビルダーの呼び出しに enableMultiInstanceInvalidation()
を組み込みます。各プロセスに AppDatabase
のインスタンスがある場合、あるプロセスで共有データベース ファイルを無効化すると、他のプロセス内の AppDatabase
のインスタンスにも自動的に反映されます。
使用方法
データ エンティティ、DAO、データベース オブジェクトを定義したら、次のコードを使用してデータベースのインスタンスを作成できます。
val db = Room.databaseBuilder( applicationContext, AppDatabase::class.java, "database-name" ).build()
AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database-name").build();
その後、AppDatabase
の抽象メソッドを使用して、DAO のインスタンスを取得できます。次に、DAO インスタンスのメソッドを使用して、データベースを操作できます。
val userDao = db.userDao() val users: List<User> = userDao.getAll()
UserDao userDao = db.userDao(); List<User> users = userDao.getAll();
参考情報
Room の詳細については、以下の参考情報をご覧ください。
サンプル
Jetcaster is a sample podcast app, built with Jetpack Compose. The goal of the sample is to showcase building with Compose across multiple form factors (mobile, TV, and Wear) and full featured architecture.
To try out this sample app, use the latest These samples showcase different architectural approaches to developing Android apps. In its different branches you'll find the same app (a TODO app) implemented with small differences.
In this branch you'll find:
User Interface built with Jetpack Learn how this app was designed and built in the design case study, architecture learning journey and modularization learning journey.
This is the repository for the Now in Android app. It is a work in progress 🚧.
Now in Android is a fully functionalJetcaster sample 🎙️
Architecture
Now in Android App