I have to show total size of two api response list . So I wait for both to be completed and use combine flow for it.
isDynamicDataLoaded is set true when all api's call completed and response data is saved in their room db. Afterwards I want to get the result at once. I am using combine flow function but it took a long time
StoreModeViewModel.kt
class StoreModeHomeViewModel : ViewModel() {
val personalOffers: Flow<List<PersonalOffer>> get() = PersonalOffersRepository.instance.getPersonalOffers()
val favoriteOffersLiveData: Flow<List<DBProduct>> get() = ProductsRepository.instance.getFavoriteOfferProductsLiveData().asFlow()
private val _isDynamicDataLoaded = MutableStateFlow(false)
val isDynamicDataLoaded = _isDynamicDataLoaded.asStateFlow()
private val personalOffersApiRequestStateFlow = PersonalOffersRepository.instance.getOffersApiRequestStatus()
private val favoriteOffersApiRequestStateFlow = ProductsRepository.instance.getFavoriteOffersApiRequestStatusLiveData()
init {
viewModelScope.launch {
val requestStateFlows = arrayListOf(
personalOffersApiRequestStateFlow,
favoriteOffersApiRequestStateFlow,
)
combine(
requestStateFlows
) { requests ->
_isDynamicDataLoaded.value =
requests.all { it?.status == ApiRequestStatus.COMPLETED }
}.collect()
}
}
fun loadData(restCaller: RestCaller) = CoreApplication.instance?.applicationContext?.let {
val workers = arrayListOf(
OneTimeWorkRequest.Builder(GetPersonalOffersWorker::class.java).setInputData(restCaller.toData()).setCancelable().build(),
OneTimeWorkRequest.Builder(GetFavoriteOfferProductsWorker::class.java).setInputData(restCaller.toData()).setCancelable().build(),
WorkManager.getInstance(it).beginUniqueWork("store_mode_data_task", ExistingWorkPolicy.KEEP, workers).enqueue()
}
}
StoreModeFragment.kt
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.isDynamicDataLoaded.collect { allDataLoaded ->
binding.progressBar.visibility = if(allDataLoaded) View.GONE else View.VISIBLE
if (allDataLoaded) {
combine(viewModel.personalOffers,viewModel.favoriteOffersLiveData){ personalOfferz, favouriteOfferz ->
personalOffersModelList.clear()
personalOffersModelList.addAll(personalOfferz.map {
PersonalOfferModel(it)
})
updateTabCounter(SwimLaneItemType.PERSONAL_OFFERS,personalOffersModelList.size)
favoriteOffersModelList.clear()
favoriteOffersModelList.addAll(favouriteOfferz.map {
FavoriteOfferModel(Product.mapFromDB(it))
})
updateTabCounter(SwimLaneItemType.FAVOURITE_OFFERS,favoriteOffersModelList.size)
val mAll = personalOffersModelList.size + favoriteOffersModelList.size
updateTabCounter(SwimLaneItemType.ALL,mAll)
selectTabAt(selectedTab)
}.collect {}
updateOrderPickUpItemView()
}
}
}
}
I have wait for both api's response to be completed and saved in room database. Then after isDynamicDataLoaded become true . I use combine to fetch both at once.
But it took long to do so. How could I improve above code...
If you need to do foreground work on a separate thread (for Db / remote api acccess) you should be using coroutines. Try running your apis in a coroutine launched on
Dispatchers.IO
instead of the Worker API. (viewModelScope.launch(Dispatchers.IO){// Your code}
)The Workers API is designed for background work that your UI is not dependent on. Like a long running task that you want to keep executing after the app goes into background