Get Flow val at once in android

58 views Asked by At

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...

1

There are 1 answers

0
Adrian Pascu On

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

WorkManager is the recommended solution for persistent work. Work is persistent when it remains scheduled through app restarts and system reboots. Because most background processing is best accomplished through persistent work, WorkManager is the primary recommended API for background processing.

enter image description here