I have some json data saved in the assets folder. I use this code to read and process it into data classes I have created:
fun getJsonDataFromAssets(context: Context, fileName: String): String =
context.assets.open(fileName).bufferedReader().use { it.readText() }
inline fun <reified T> extractJsonData(context: Context, jsonName: String): List<T> {
val jsonList = JSONArray(getJsonDataFromAssets(context, jsonName))
val gson = Gson()
val extractedList = mutableListOf<T>()
for (i in 0 until jsonList.length()) {
val jsonObject = jsonList.getJSONObject(i).toString()
val elementOfT = gson.fromJson(jsonObject, T::class.java)
extractedList.add(elementOfT)
}
return extractedList
}
Then I add those data classes to my room db callback with this code:
private class DatabaseCallback(
private val context: Context,
private val scope: CoroutineScope
) :
RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
instance?.let { database ->
scope.launch {
val ownerDao = database.ownerDao()
val dogDao = database.dogDao()
val catDao = database.catDao()
initializeList("owner.json", ownerDao)
initializeList("dog.json", dogDao)
initializeList("cat.json", catDao)
}
}
}
suspend inline fun <reified T> initializeList(jsonName:String, dao: IDao<T>) {
val jsonList = extractJsonData<T>(context, jsonName)
dao.addAllT(jsonList)
}
}
In my main activity I observe Livedata and use it to populate a recyclerview as soon as the app launches. However this make the recyclerview blank for some time.
How can I add a progress bar or whatever else until the database has been created?
In general, I would handle this by using Room's support for populating your database from an asset. That's a relatively recent addition to the Room API, and it should be faster than what you have.
Ignoring that, you would need to pass something into your DatabaseCallback
constructor (e.g., a function type) that could be called from your onCreate()
function when your work is completed. Whatever is creating your database (e.g., a repository) would provide that DatabaseCallback
constructor parameter and deal with the result.
So, for example, your constructor could be:
private class DatabaseCallback(
private val context: Context,
private val scope: CoroutineScope,
private val onDone: () -> Unit
)
...and onCreate()
could call onDone()
after inserting all the entries. Or, onDone
could be a Channel
on which you offer()
the result. Whoever is creating the DatabaseCallback
would supply the lambda expression or Channel
or whatever, then use that to find out when the work completed.