Mengisi otomatis database Room Anda

Jika Anda ingin aplikasi dimulai dengan database yang sudah terisi dengan sekumpulan data tertentu, Anda dapat mengisi database sebelumnya. Di Room, Anda dapat menggunakan API untuk mengisi database terlebih dahulu saat melakukan inisialisasi dengan konten dari file database dalam bentuk paket di sistem file perangkat.

Mengisi otomatis dari aset aplikasi

Untuk mengisi otomatis database Room dari file database dalam bentuk paket yang terletak di mana saja pada direktori assets/ aplikasi Anda, panggil fungsi createFromAsset dari objek RoomDatabase.Builder Anda sebelum memanggil build:

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

Fungsi createFromAsset menerima argumen string yang berisi jalur relatif dari direktori assets/ ke file database dalam bentuk paket.

Mengisi otomatis dari sistem file

Untuk mengisi database Room terlebih dahulu dari file database dalam bentuk paket yang terletak di mana saja pada sistem file perangkat kecuali direktori assets/ aplikasi Anda, panggil fungsi createFromFile dari objek RoomDatabase.Builder Anda sebelum memanggil build:

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

Fungsi createFromFile menerima argumen File untuk file database dalam bentuk paket. Room membuat salinan file yang ditetapkan, bukan membukanya secara langsung, jadi pastikan aplikasi Anda memiliki izin baca pada file tersebut.

Menangani migrasi yang menyertakan database dalam bentuk paket

File database dalam bentuk paket juga dapat mengubah cara database Room Anda menangani migrasi penggantian. Biasanya, saat migrasi destruktif diaktifkan dan Room harus melakukan migrasi tanpa jalur migrasi, Room akan menghapus semua tabel dalam database dan membuat database kosong dengan skema yang ditentukan untuk versi target. Namun, jika Anda menyertakan file database dalam bentuk paket dengan jumlah yang sama seperti versi target, Room akan mengisi database yang baru dibuat ulang dengan konten file database dalam bentuk paket setelah melakukan migrasi destruktif.

Untuk mengetahui informasi selengkapnya tentang migrasi database Room, lihat Memigrasikan database Room.

Bagian berikut menampilkan beberapa contoh cara kerja migrasi ini dalam praktiknya.

Contoh: Migrasi penggantian dengan database dalam bentuk paket

Ambil contoh:

  • Aplikasi Anda menentukan database Room di versi 3.
  • Instance database yang sudah diinstal di perangkat berada di versi 2.
  • Ada file database dalam bentuk paket yang berada di versi 3.
  • Tidak ada jalur migrasi yang diimplementasikan dari versi 2 ke versi 3.
  • Migrasi destruktif diaktifkan.

// 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()
}

Berikut yang akan terjadi dalam situasi ini:

  1. Karena database yang ditentukan dalam aplikasi Anda berada di versi 3 dan instance database yang sudah diinstal di perangkat berada di versi 2, migrasi diperlukan.
  2. Karena tidak ada rencana migrasi yang diimplementasikan dari versi 2 ke versi 3, migrasi yang diimplementasikan adalah migrasi fallback.
  3. Karena Anda memanggil fungsi builder fallbackToDestructiveMigration, migrasi fallback bersifat destruktif. Room akan menghapus instance database yang terinstal pada perangkat.
  4. Karena ada file database dalam bentuk paket yang berada di versi 3, Room akan membuat ulang database dan mengisinya menggunakan konten file database dalam bentuk paket. Jika file database yang telah dipaketkan berada di versi 2, Room akan menentukan bahwa file tersebut tidak cocok dengan versi target dan tidak menggunakannya untuk migrasi penggantian.

Contoh: Migrasi yang diimplementasikan dengan database dalam bentuk paket

Anggaplah aplikasi Anda mengimplementasikan jalur migrasi dari versi 2 ke versi 3 sebagai gantinya:

// 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()
}

Berikut yang akan terjadi dalam situasi ini:

  1. Karena database yang ditentukan di aplikasi Anda berada di versi 3 dan database yang sudah diinstal pada perangkat berada di versi 2, migrasi diperlukan.
  2. Karena ada jalur migrasi yang diimplementasikan dari versi 2 ke versi 3, Room akan menjalankan fungsi migrate yang ditentukan untuk mengupdate instance database di perangkat ke versi 3, yang mempertahankan data yang sudah ada dalam database. Room tidak menggunakan file database dalam bentuk paket karena Room hanya menggunakan file database tersebut jika terjadi migrasi fallback.

Contoh: Migrasi multi-langkah dengan database dalam bentuk paket

File database dalam bentuk paket juga dapat memengaruhi migrasi yang terdiri dari beberapa langkah. Pertimbangkan kasus berikut:

  • Aplikasi Anda menentukan database Room di versi 4.
  • Instance database yang sudah diinstal di perangkat berada di versi 2.
  • Ada file database dalam bentuk paket yang berada di versi 3.
  • Ada jalur migrasi yang diimplementasikan dari versi 3 ke versi 4, tetapi bukan dari versi 2 ke versi 3.
  • Migrasi destruktif diaktifkan.

// 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()
}

Berikut yang akan terjadi dalam situasi ini:

  1. Karena database yang ditentukan dalam aplikasi Anda berada di versi 4 dan instance database yang sudah diinstal di perangkat berada di versi 2, migrasi diperlukan.
  2. Karena tidak ada jalur migrasi yang diimplementasikan dari versi 2 ke versi 3, migrasi yang diimplementasikan adalah migrasi fallback.
  3. Karena Anda memanggil fungsi builder fallbackToDestructiveMigration, migrasi fallback bersifat destruktif. Room akan meletakkan instance database pada perangkat.
  4. Karena ada file database dalam bentuk paket yang berada di versi 3, Room akan membuat ulang database dan mengisinya menggunakan konten file database dalam bentuk paket.
  5. Database yang diinstal di perangkat kini berada di versi 3. Karena versi ini masih lebih rendah daripada versi yang ditentukan di aplikasi Anda, migrasi lain diperlukan.
  6. Karena ada jalur migrasi yang diimplementasikan dari versi 3 ke versi 4, Room akan menjalankan fungsi migrate yang ditentukan untuk mengupdate instance database di perangkat ke versi 4, yang mempertahankan data yang disalin dari file database dalam bentuk paket versi 3.