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

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

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

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

Kotlin

Room.databaseBuilder(appContext, AppDatabase::class.java, "Sample.db")
    .createFromAsset("database/myapp.db")
    .build()

Java

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .build();

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

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

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

Kotlin

Room.databaseBuilder(appContext, AppDatabase::class.java, "Sample.db")
    .createFromFile(File("mypath"))
    .build()

Java

Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromFile(new File("mypath"))
    .build();

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

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

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

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

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

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

次の前提で説明します。

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

Kotlin

// Database class definition declaring version 3.
@Database(version = 3)
abstract class AppDatabase : RoomDatabase() {
    ...
}

// Destructive migrations are enabled and a prepackaged database
// is provided.
Room.databaseBuilder(appContext, AppDatabase::class.java, "Sample.db")
    .createFromAsset("database/myapp.db")
    .fallbackToDestructiveMigration()
    .build()

Java

// Database class definition declaring version 3.
@Database(version = 3)
public abstract class AppDatabase extends RoomDatabase {
    ...
}

// Destructive migrations are enabled and a prepackaged database
// is provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .fallbackToDestructiveMigration()
    .build();

この場合は、次のようになります。

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

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

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

Kotlin

// Database class definition declaring version 3.
@Database(version = 3)
abstract class AppDatabase : RoomDatabase() {
    ...
}

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

// A prepackaged database is provided.
Room.databaseBuilder(appContext, AppDatabase::class.java, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_2_3)
    .build()

Java

// Database class definition declaring version 3.
@Database(version = 3)
public abstract class AppDatabase extends RoomDatabase {
    ...
}

// Migration path definition from version 2 to version 3.
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        ...
    }
};

// A prepackaged database is provided.
Room.databaseBuilder(appContext, AppDatabase.class, "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 への移行パスは実装されていない。
  • 破壊的移行が有効になっている。

Kotlin

// Database class definition declaring version 4.
@Database(version = 4)
abstract class AppDatabase : RoomDatabase() {
    ...
}

// Migration path definition from version 3 to version 4.
val MIGRATION_3_4 = object : Migration(3, 4) {
    override fun migrate(database: SupportSQLiteDatabase) {
        ...
    }
}

// Destructive migrations are enabled and a prepackaged database is
// provided.
Room.databaseBuilder(appContext, AppDatabase::class.java, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_3_4)
    .fallbackToDestructiveMigration()
    .build()

Java

// Database class definition declaring version 4.
@Database(version = 4)
public abstract class AppDatabase extends RoomDatabase {
    ...
}

// Migration path definition from version 3 to version 4.
static final Migration MIGRATION_3_4 = new Migration(3, 4) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        ...
    }
};

// Destructive migrations are enabled and a prepackaged database is
// provided.
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
    .createFromAsset("database/myapp.db")
    .addMigrations(MIGRATION_3_4)
    .fallbackToDestructiveMigration()
    .build();

この場合は、次のようになります。

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

参考情報

Room データベースの事前取り込みの詳細については、次の参考情報をご覧ください。

動画

ブログ