简体   繁体   中英

Wait for coroutine to finish to handle user click

I'm making a system of "sessions" where the user can launch, finish and view his session.
The user go through a first fragment to create his session and then go into a fragment "in session".
If he return to the main menu before finishing his session, I want him to go directly to "in session" without going through the "new session" fragment.

All session data are stored into a local database and I use Kotlin coroutines to fetch data from the db (see code example below)

It's my first time using coroutine, and I will admit it's a bit fuzzy for me, all the help is welcome

The problem is that when the user press the bouton to navigate, the coroutine finish after the verification to see if there is a current session, that lead to verify a null object or the previous session of the current session, and so navigate to a the "new session" fragment

What I need is a way to wait for the coroutine to finish and then handle the button click

All the code wrote here is contain inside inside the viewModel .
This is how I setup the Job/Scope

private var viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

And this is how I launch the coroutine:

private fun initializeLastSession() {
    uiScope.launch {
    lastSession.value = getLastSessionFromDatabase()
    }
}

private suspend fun getLastSessionFromDatabase(): Session? {
    return withContext(Dispatchers.IO) {
        var session = database.getLastSession()
        session
    }
}

The verification is made inside this function

fun isSessionActive(): Boolean {
//Simplified
    if (lastSession.value = null) {
        return false
    } else if (...) {
        return true
    } else {
        return false
    }

This last function "isSessionActive" is called from an if statement from the fragment itlsef, when the user press the navigation button.
If it's true then it navigate to "InSession", else in "newSession"

I've seen multiple way of waiting for a coroutine to finish but none match the way I launch it, and even less have a solution that has worked for me.

Would you allow me with a simple example unrelated to your code? But strongly related to the problem:

uiScope.launch{
 withContext(Dispatchers.IO){
  val dataFromDatabase = getSomeDataFromDatabase()
  if (dataFromDatabase.notEmpty()){ //or something
    withContext(Dispatchers.Main){
     //send data to fragment here :)
    }
   }
 }
}

EDIT:

Since you stated you are in the ViewModel , you don't need to return any value, you need to observe that changed value:

//on top of your ViewModel class: 

val yourVariableName: MutableLiveData<Boolean> = MutableLiveData()

//than in your method: 
    uiScope.launch{
     withContext(Dispatchers.IO){
      val dataFromDatabase = getSomeDataFromDatabase()
      if (dataFromDatabase.notEmpty()){ //or something
        withContext(Dispatchers.Main){
         if (lastSession.value = null) {
        yourVariableName.value = false
    } else if (...) {
        yourVariableName.value = true
    } else {
        yourVariableName.value = false
    }
        }
       }
     }
    }

And than in your fragment:

//after you have successfully instantiated the `ViewModel`: 
mViewModel.yourVariableName.observe(this , Observer{ valueYouAreObserving->
 // and here you have the value true ore false 
 Log.d("Tag", $valueYouAreObserving)
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM