Room データベースを事前に取り込む

アプリを起動する際に、特定のデータセットをすでに読み込んでいるデータベースを使用したい場合は、データベースを事前取り込みできます。Room では、API を使用して、初期化時にデバイスのファイル システム内にある事前パッケージ化済みデータベース ファイルの内容をデータベースに事前取り込みできます。

createFromAssetcreateFromFile

アプリアセットから事前取り込みする

事前パッケージ化済みデータベース ファイルから Room データベースに事前取り込みする際、データベース ファイルがアプリの assets/ ディレクトリ内にある場合は、次のように createFromAsset 関数を RoomDatabase.Builder オブジェクトから呼び出してから、build を呼び出します。

Room.databaseBuilder<AppDatabase>(appContext, "sample.db")
    .createFromAsset("database/myapp.db")
    .build()

createFromAsset 関数は、assets/ ディレクトリから事前パッケージ化済みデータベース ファイルへの相対パスが入った文字列引数を受け付けます。

ファイル システムから事前取り込みする

事前パッケージ化済みデータベース ファイルから Room データベースに事前取り込みする際、データベース ファイルがデバイスのファイル システムでアプリの assets/ ディレクトリの外にある場合は、RoomDatabase.Builder オブジェクトから createFromFile 関数を呼び出してから、build を呼び出します。

Room.databaseBuilder<AppDatabase>(appContext, "sample.db")
    .createFromFile(File("mypath"))
    .build()

createFromFile 関数は、File 引数を受け付けます。事前パッケージ化済みデータベース ファイルの Room で指定されたファイルが直接開かれるのではなく、コピーが作成されるため、アプリにファイルの読み取り権限があることを確認してください。

事前パッケージ化済みデータベースを含む移行の処理

事前パッケージ化済みデータベース ファイルによって、Room データベースでのフォールバック移行の処理方法も変わります。通常、破壊的移行が有効で 、Room が移行パスなしで移行を実施する必要がある場合、Room はデータベース内のすべての テーブルを削除し、ターゲット バージョンの指定されたスキーマで空のデータベースを 作成します。ただし、ターゲット バージョンと同じ番号の事前パッケージ化済みデータベース ファイルを含めると、破壊的移行の実行後に、事前パッケージ化済みデータベース ファイルの内容が新規に再作成されたデータベースに取り込まれます。

Room データベースの移行の詳細については、 Room データベースを移行するをご覧ください。

以降のセクションでは、実際の動作の例を紹介します。

例: 事前パッケージ化済みデータベースを含むフォールバック移行

次の前提で説明します。

  • バージョン 3 で Room データベースを定義している。
  • デバイスにインストールされているデータベース インスタンスはバージョン 2 である。
  • バージョン 3 の事前パッケージ化済みデータベース ファイルがある。
  • バージョン 2 からバージョン 3 への移行パスは実装されていない。
  • 破壊的移行が有効になっている。

// Database class definition declaring version 3.
@Database(entities = [SampleEntity::class], version = 3)
abstract class FallbackAppDatabase : RoomDatabase() {
    // ...
}

fun createFallbackDb(appContext: Context) {
    Room.databaseBuilder<FallbackAppDatabase>(appContext, "sample.db")
        .createFromAsset("database/myapp.db")
        .fallbackToDestructiveMigration()
        .build()
}

この状況では、次のようになります。

  1. アプリで定義されたデータベースがバージョン 3 で、デバイスにインストールされているデータベース インスタンスはバージョン 2 であるため、移行が必要です。
  2. バージョン 2 からバージョン 3 への移行プランが実装されていないため、この移行はフォールバック移行です。
  3. fallbackToDestructiveMigration ビルダー 関数を呼び出すため、フォールバック移行は破壊的移行です。Room は、デバイスにインストールされているデータベース インスタンスを削除します。
  4. バージョン 3 の事前パッケージ化済みデータベース ファイルがあるため、Room によってデータベースが再作成され、事前パッケージ化済みデータベース ファイルの内容が取り込まれます。事前パッケージ化済みデータベース ファイルがバージョン 2 の場合は、ターゲット バージョンと一致せず、フォールバック移行では使用されないことが通知されます。

例: 事前パッケージ化済みデータベースを含む実装済みの移行

次のように、バージョン 2 からバージョン 3 への移行パスを実装するとします。

// Database class definition declaring version 3.
@Database(entities = [SampleEntity::class], version = 3)
abstract class ImplementedAppDatabase : RoomDatabase() {
    // ...
}

// Migration path definition from version 2 to version 3.
val MIGRATION_2_3 = object : Migration(2, 3) {
    override suspend fun migrate(connection: SQLiteConnection) {
        // ...
    }
}

fun createImplementedDb(appContext: Context) {
    Room.databaseBuilder<ImplementedAppDatabase>(appContext, "sample.db")
        .createFromAsset("database/myapp.db")
        .addMigrations(MIGRATION_2_3)
        .build()
}

この状況では、次のようになります。

  1. アプリで定義されたデータベースがバージョン 3 で、デバイスにインストールされているデータベースはバージョン 2 であるため、移行が必要です。
  2. バージョン 2 からバージョン 3 への移行パスが実装されているため、 定義されている migrate 関数が実行され、すでにデータベースにあるデータを維持したまま、デバイス上のデータベース インスタンスがバージョン 3 に更新されます。フォールバック移行の場合にのみ事前パッケージ化済みデータベース ファイルが使用されるため、事前パッケージ化済みデータベース ファイルは使用されません。

例: 事前パッケージ化済みデータベースを含むマルチステップ移行

事前パッケージ化済みデータベース ファイルは、複数のステップで構成される移行にも影響します。次の場合を考えます。

  • バージョン 4 で Room データベースを定義している。
  • デバイスにインストールされているデータベース インスタンスはバージョン 2 である。
  • バージョン 3 の事前パッケージ化済みデータベース ファイルがある。
  • バージョン 3 からバージョン 4 への移行パスは実装されているが、バージョン 2 からバージョン 3 への移行パスは実装されていない。
  • 破壊的移行が有効になっている。

// Database class definition declaring version 4.
@Database(entities = [SampleEntity::class], version = 4)
abstract class MultiStepAppDatabase : RoomDatabase() {
    // ...
}

val MIGRATION_3_4 = object : Migration(3, 4) {
    override suspend fun migrate(connection: SQLiteConnection) {
        // ...
    }
}

fun createMultiStepDb(appContext: Context) {
    Room.databaseBuilder<MultiStepAppDatabase>(appContext, "sample.db")
        .createFromAsset("database/myapp.db")
        .addMigrations(MIGRATION_3_4)
        .fallbackToDestructiveMigration()
        .build()
}

この状況では、次のようになります。

  1. アプリで定義されたデータベースがバージョン 4 で、デバイスにインストールされているデータベース インスタンスはバージョン 2 であるため、移行が必要です。
  2. バージョン 2 からバージョン 3 への移行パスが実装されていないため、この移行はフォールバック移行です。
  3. fallbackToDestructiveMigration ビルダー 関数を呼び出すため、フォールバック移行は破壊的移行です。Room により、デバイス上のデータベース インスタンスが削除されます。
  4. バージョン 3 の事前パッケージ化済みデータベース ファイルがあるため、Room によってデータベースが再作成され、事前パッケージ化済みデータベース ファイルの内容が取り込まれます。
  5. 現在、デバイスにインストールされているデータベースはバージョン 3 です。アプリで定義されているバージョンよりも低いため、別の移行が必要です。
  6. バージョン 3 からバージョン 4 への移行パスが実装されているため、 定義されている migrate 関数が実行され、バージョン 3 の事前パッケージ化済みデータベース ファイルから上書きコピーされたデータを維持したまま、デバイス上のデータベース インスタンスをバージョン 4 に更新します。