Search code examples
androidkotlinretrofitkotlin-coroutinesandroid-livedata

App slow after making a request inside another request


I am making a request with coroutines based on a user name, which returns a list of Object<Profile>, and with that list I am making another request with each object, and then switching and passing the info to another screen, but such process is making the app super slow and I would like to find a better way or a way to not making this process so slow. Here my code

Fragment from where I am starting the process and where the app is getting super slow

 emptyHomeViewModel.getPlayersListByName(text)
                emptyHomeViewModel.listOfPlayersByNameLiveData.observe(viewLifecycleOwner) { playersByName ->
                    emptyHomeViewModel.getPlayersProfileByName(playersByName)
                    emptyHomeViewModel.listOfProfilesByID.observe(viewLifecycleOwner) { profiles ->
                        if (profiles != null) {
                            val list: Array<Profile> = profiles.toTypedArray()
                            bundle = Bundle().apply {
                                putSerializable("user", list)
                            }
                            findNavController().navigate(
                                R.id.action_emptyHomeFragment_to_selectUserFragment,
                                bundle
                            )
                        }
                    }
                }

ViewModel from where I am executing the coroutines and making the request to the API

 fun getPlayersListByName(playerName: String) = viewModelScope.launch {
        val playersList = getPlayersByPersonaNameUseCase.getPlayersByName(playerName)
        if (playersList != null) {
            _listOfPlayersByNameLiveData.postValue(playersList)
        }
    }


 fun getPlayersProfileByName(playersByName: List<PlayerByPersonaNameItem>?) =
        viewModelScope.launch {
            var playersProfileList: ArrayList<Profile> = arrayListOf()
            if (playersByName != null) {
                for (player in playersByName) {
                    getPlayerByIDUseCase.getPlayerById(player.accountId)
                        ?.let { playersProfileList.add(it) }
                }
                _listOfProfilesByID.postValue(playersProfileList)
            }
        }

Solution

  • You can actually load profiles in parallel, preventing loading them one after another, to decrease time of loading data:

    fun getPlayersProfileByName(playersByName: List<PlayerByPersonaNameItem>?) =
        viewModelScope.launch {
            val playersProfileList: List<Profile> = playersByName?.map { player ->
                async {
                    getPlayerByIDUseCase.getPlayerById(player.accountId)
                }
            }.awaitAll().filterNotNull()
            _listOfProfilesByID.postValue(playersProfileList)
        }
    

    Also you can improve it a little bit by removing additional LiveData observer and calling getPlayersProfileByName right after you get playersList:

    fun getPlayersListByName(playerName: String) = viewModelScope.launch {
        val playersList = getPlayersByPersonaNameUseCase.getPlayersByName(playerName)
        getPlayersProfileByName(playersList)
    }