有時,您可能希望讓應用程式首先處理已載入特定資料集的資料庫。這稱為預先填入資料庫。在 Room 2.2.0 及以上版本中,您可以使用 API 方法在初始化時,使用裝置檔案系統中預先封裝的資料庫檔案內容來預先填充 Room 資料庫。
從應用程式素材資源預先填入
如要從位於應用程式 assets/
目錄任意位置的預先封裝資料庫檔案中預先填入 Room 資料庫,請先透過 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 資料庫遷移作業,請參閱遷移 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();
在這種情況下會發生下列情況:
- 由於應用程式中定義了第 3 版資料庫,而裝置上已經安裝的資料庫執行個體為第 2 版,因此必須遷移。
- 由於沒有實作從第 2 版到第 3 版的遷移計畫,因此這項遷移作業屬於備援遷移作業。
- 由於系統會呼叫
fallbackToDestructiveMigration()
建構工具方法,因此備用遷移作業具有破壞性。Room 會捨棄裝置上已經安裝的資料庫執行個體。 - 由於存在第 3 版預先封裝的資料庫檔案,因此 Room 會重新建立該資料庫,並填入預先封裝的資料庫檔案內容。另一方面,如果預先封裝的資料庫檔案為第 2 版,則 Room 會注意到其與目標版本不符,而且不會用於備份遷移作業。
範例:實作預先封裝的資料庫遷移作業
假設應用程式實作了從第 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();
在這種情況下會發生下列情況:
- 由於應用程式中定義了第 3 版資料庫,而裝置上已經安裝的資料庫為第 2 版,因此必須遷移。
- 由於已經實作從第 2 版到第 3 版的遷移路徑,因此 Room 會執行定義的
migrate()
方法,將裝置上的資料庫執行個體更新為第 3 版,並保留資料庫中已有的資料。Room 不會使用預先封裝的資料庫檔案,因為 Room 只會在備用遷移作業時使用預先封裝的資料庫檔案。
範例:預先封裝資料庫的多步驟遷移
預先封裝的資料庫檔案還會影響包含多個步驟的遷移作業。假設下列情況:
- 應用程式定義了第 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();
在這種情況下會發生下列情況:
- 由於應用程式中定義了第 4 版資料庫,而裝置上已經安裝的資料庫執行個體為第 2 版,因此必須遷移。
- 由於沒有實作從第 2 版到第 3 版的遷移路徑,因此這項遷移作業屬於備援遷移作業。
- 由於系統會呼叫
fallbackToDestructiveMigration()
建構工具方法,因此備用遷移作業具有破壞性。Room 會捨棄裝置上的資料庫執行個體。 - 由於存在第 3 版預先封裝的資料庫檔案,因此 Room 會重新建立該資料庫,並填入預先封裝的資料庫檔案內容。
- 裝置上安裝的資料庫版本現在為第 3 版。但仍然低於應用程式中定義的版本,因此必須再次進行遷移。
- 由於已經實作從第 3 版到第 4 版的遷移路徑,因此 Room 會執行定義的
migrate()
方法,將裝置上的資料庫執行個體更新為第 4 版,並保留從第 3 版預先封裝的資料庫檔案中複製的資料。
其他資源
如要進一步瞭解如何預先填入 Room 資料庫,請參閱下列其他資源。
影片
- Room 最新消息 (2019 年 Android 開發人員高峰會)