3

I have a suspend function userRepo.updateUserWithNewPersonalDetails(details) and after executing this function I want to execute success() function which is a call back.

but the issue is success() is not getting executed.

any suggestions on how to get this to work.

this sequence does not work

  SUCCESS -> {
                        progress.postValue(GONE)
                        userRepo.updateUserWithNewPersonalDetails(details) // EXECUTED
                        success() // NOT EXECUTED
                    }

if I change it to call success() first then save to repo, it works fine. but this is not the right way of doing it I think.

could you suggest please

  SUCCESS -> {
                        progress.postValue(GONE)
                        success() // EXECUTED
                        userRepo.updateUserWithNewPersonalDetails(details) // EXECUTED
                    }

Fragment call

viewModel.save(personalDetails) { activity?.onBackPressed() }

ViewModel

fun save(details: PersonalDetails, success: () -> Unit) {
    viewModelScope.launch {
        userRepo.savePersonalDetails(details).collect {
            when (it.status) {
                LOADING -> {
                    progress.postValue(VISIBLE)
                }
                SUCCESS -> {
                    progress.postValue(GONE)
                    userRepo.updateUserWithNewPersonalDetails(details)
                    success() // THIS IS NOT EXECUTED
                }
                ERROR -> {
                    progress.postValue(GONE)
                    error.postValue(ErrorResult(errorCode = SNACKBAR_ID_USER_DETAILS_SAVE_FAIL))
                }
            }
        }
    }
}

userRepository

suspend fun updateUserWithNewPersonalDetails(details: PersonalDetails) {
        userDao.get().collect { cachedUser ->
            val updatedCachedUser = UserDB(cachedUser.id, etc..)
            userDao.save(updatedCachedUser)
        }
    }
BRDroid
  • 3,920
  • 8
  • 65
  • 143

2 Answers2

0

Can you please show me the function that you call?, did you already use the breakpoint to make sure the function it self was called?. cause if you dont, i think you might use nullable variable and the value will retrieved after the suspend function (userRepo.blabla()) finished, if yes. maybe you can call .invokeOnCompletion { /your Success Function/ success() }

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
  • you mean userRepo.updateUserWithNewPersonalDetails(details).invoke? I cannot do invoke on this, not recognisable – BRDroid Feb 10 '22 at 16:10
  • no, wrap with coroutine like this CoroutineScope(Dispatcher.IO).launch{ you're usecase}.invokeOnComplete{} – AL QUDRI Feb 11 '22 at 16:53
0

success() method isn't called because you collect Flow in updateUserWithNewPersonalDetails method:

userDao.get().collect {...}

It suspends a coroutine execution. My guess is that it is an infinite Flow, which doesn't complete until coroutine is completed. That's why userDao.get().collect suspends execution.


I don't quite understand what you are trying to achieve in the updateUserWithNewPersonalDetails method, but it seems it doesn't update the DB. If you want to update user details in the DB, you don't need to collect Flow. You should have something like this:

suspend fun updateUserWithNewPersonalDetails(details: PersonalDetails) {
    userDao.update(details)
}

where userDao.update(details) is a suspend method, which updates DB:

suspend fun update(details: PersonalDetails)
Sergio
  • 27,326
  • 8
  • 128
  • 149
  • Hello @sergey main issue was `success()` was not executed when it was written after `userRepo.updateUserWithNewPersonalDetails(details)`, and I want to execute `success()` once the `userRepo.updateUserWithNewPersonalDetails(details)` is executed. AM I WRONG IN THINKING THIS IS HOW IT SHOULD WORK? – BRDroid Feb 10 '22 at 16:55
  • Hello, you can't do that. Because of the reason I mentioned in my answer. The `Flow` you collect is infinite, so `updateUserWithNewPersonalDetails` will never finish execution. – Sergio Feb 10 '22 at 16:56
  • okay, so I can just call `success()` first then call `userRepo.updateUserWithNewPersonalDetails(details)` is that acceptable to do? – BRDroid Feb 10 '22 at 16:58
  • I don't know, if you OK with successfully saving details calling `userRepo.savePersonalDetails` method then it is OK. Usually DB is updated in the Repository after server is successfully updated. So I can also suggest updating the DB in the `userRepo.savePersonalDetails` method. – Sergio Feb 10 '22 at 17:02
  • Hello sorry I did not understand what u exactly mean by`OK` `I don't know, if you OK with successfully saving details` – BRDroid Feb 10 '22 at 17:06
  • It's up to you how you organize your code, but, in my opinion, what you are doing in `updateUserWithNewPersonalDetails` method is wrong. You shouldn't collect a Flow there, you need just update DB, according to your code you don't do it. Even `details` parameter, which is passed to `updateUserWithNewPersonalDetails` method is not used. – Sergio Feb 10 '22 at 17:09
  • suspend fun updateUserWithNewPersonalDetails(details: PersonalDetails) { return userDao.get().collect { cachedUser -> val updatedCachedUser = UserDB(cachedUser.id, cachedUser.paymentCustomerId, cachedUser.phoneNumber, details.firstName, cachedUser.imageUrl, cachedUser.driverLicenseId, cachedUser.groupIds) userDao.save(updatedCachedUser) } } – BRDroid Feb 10 '22 at 17:14
  • i removed the use of details from the function just to make it simpler to look at – BRDroid Feb 10 '22 at 17:15
  • what do you recommend the function should be updateUserWithNewPersonalDetails – BRDroid Feb 10 '22 at 17:15
  • can you create a suspend method in `userDao` which returns cached user? Something like this: `suspend fun getUser(): User`. Then in `updateUserWithNewPersonalDetails` you will use next lines of code: `val cachedUser = userDao.getUser(); val updatedCachedUser = UserDB(cachedUser.id, etc..); userDao.save(updatedCachedUser)`; – Sergio Feb 10 '22 at 17:28
  • A Flow doesn’t have to be hot to be infinite. For example, the flows returned by Room DAOs are infinite cold flows. – Tenfour04 Feb 11 '22 at 01:13