We know that LiveData is Lifecycle aware and if there's a configuration change LiveData object doesn't re-query from Database (local/remote) each and every time and it gets updated only if there's any update in the data.
Recently I started using Kotlin Flow, I should admit that it's best for the data layer, that is for implementing in the repo so that ViewModel is notified. But I used the Kotlin Flow in ViewModel/View layer also so that I collect the Flow objects in the Fragment directly based on its Status (sealed class implementation). The problem I encountered in this usage of Flow is each and every time when there is a configuration change data is being retrieved from the Database (local/remote).
What should be done in this case? Is there a way to avoid re-querying while using Flow or should I only use LiveData in the ViewModel/View Layer?
Sample Code
sealed class Status<T> {
class Processing<T> : Status<T>()
data class Completed<T>(val value: T) : Status<T>()
data class Error<T>(val error: String) : Status<T>()
companion object {
fun <T> processing() = Processing<T>()
fun <T> completed(value: T) = Completed(value)
fun <T> error(error: String) = Error<T>(error)
}
}
Repo:
class Repo(database: LocalDatabase){
fun retrieveUsersData() = flow<Status<List<Users>>>{
emit(Status.processing())
database.dao.getUsers().collect{
// Assume db queries successfully and returns list of users
emit(Status.completed(it))
}
}.catch {
emit(Status.error(it.error.toString()))
}.flowOn(Dispatchers.IO)
}
ViewModel:
class MyViewModel(application: Application): AndroidViewModel(application)
{
private val db = LocalDatabase.getInstance(application)
private val repo = Repo(db)
val usersData= repo.retrieveUsersData(dataCollectionType)
}
Fragment:
class UsersFragment: Fragment(){
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Assume all the declarations are done properly
coroutineScope.launch {
retrieveUsersData()
}
}
private suspend fun retrieveUsersData(){
viewModel.retrieveUsersData().collect{ status ->
// Based on the Status do the actions.
// When Status is Completed set the data to the adapter.
}
}
} // end of Fragment