今回のアプリケーションでは、必要なかったのですが、データベースの初期化に続けてテーブルを初期化する処理を作成します。
テーブルの初期化は、初期データを記述したJSONファイルを準備して、JSONのキーをRoomのエンティティにマッピングすることにより行います。
これにより、テーブルごとに初期化処理を書く必要がなくなります。
マッピングには、Googleが提供する**Gson**ライブラリを使用します。
バージョンカタログファイルにGsonの定義を追記します。
[versions]
:
gson = "2.13.2" # https://mvnrepository.com/artifact/com.google.code.gson/gson
[libraries]
:
gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
:
追記後、『Sync Now』で内容をプロジェクトに反映させます。
:core:dataモジュールのbuild.gradle.ktsにGsonライブラリの依存を追記します。
:
dependencies {
:
implementation(libs.gson)
:
}
追記後、『Sync Now』で内容をプロジェクトに反映させます。
テーブルの初期化処理では、一括INSERTを行いますので、DAOへ追記します。
下記は、RouteDaoの例です。
※初期化処理では、一括INSERTのメソッド名を検索しますので、初期化するすべてのテーブルのDAOでメソッド名を合わせておきます。
: @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertAll(routes: List<Route>): List<Long> :
テーブルの初期化処理が終了する前に、画面の操作がされないように同期処理で初期化処理を実行します。
:appモジュールのPortalApplication.ktを変更します。
:
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
:
class HiltApplication: Application() {
:
private fun initializeDatabase() {
runBlocking {
withContext(Dispatchers.IO) {
databaseInitializer.initialize()
}
}
}
}
データベース初期化処理にテーブルの初期化処理を追記します。
:
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
:
class DatabaseInitializer @Inject constructor(
private val database: AppDatabase
private val database: AppDatabase,
@param:ApplicationContext
private val context: Context
) {
private var isInitialized = false
private val basePackage = "${context.packageName}.core.data"
private val assetsDir = "tableInitialData"
:
fun initialize(): Boolean {
return if (isInitialized()) {
// データベースは既に開いています
true
} else {
// データベースを開きます(存在しない場合は作成されます)
database.openHelper.writableDatabase.isOpen
// テーブルを初期化します
initializeTables()
isInitialized = true
true
}
}
/**
* assets/tableInitialDataディレクトリ内のJSONファイルでテーブルを初期化
*/
private suspend fun initializeTables() {
// assetsディレクトリ内のJSON初期化ファイルを取得
val fileNames = context.assets.list(assetsDir) ?: emptyArray()
for (fileName in fileNames) {
if (!fileName.endsWith(".json")) continue
val entityName = fileName.substringBeforeLast('.')
loadAndInsert(context, database, entityName, "${assetsDir}/${fileName}")
}
}
/**
* JSON初期化ファイルの内容でテーブルにレコードを全件INSERT
*/
private suspend fun loadAndInsert(context: Context, database: RoomDatabase, entityName: String, assetPath: String) {
val entityClass = Class.forName("${basePackage}.${entityName}")
val daoClass = Class.forName("${basePackage}.${entityName}Dao")
// JSON初期化ファイルから初期化データを取得します
val json = context.assets.open(assetPath).bufferedReader().use { it.readText() }
val listType = TypeToken.getParameterized(List::class.java, entityClass).type
val entities = Gson().fromJson<List<*>>(json, listType)
// INSERTするテーブルのDAOを取得します
val daoGetter = "${entityName}Dao"
val daoInstance = database.javaClass.getMethod(daoGetter).invoke(database)
// insertAllを呼び出します
val insertMethod = daoInstance::class.java.getMethod("insertAll", List::class.java)
insertMethod.invoke(daoInstance, entities)
}
}
初期化データは、/core/data/src/main/assets/tableInitialDataディレクトリ内にJSON形式で用意します。
ファイル名は、エンティティ名.jsonにします。
エミュレーターを起動して、アプリケーションを実行します。
※データベースは実行前に削除しておきます。
※Device Manager➡Wipe Dataでエミュレーターを初期化できます。
App Inspectionでレコードが作成されていることを確認します。