0

I have code like

viewModelScope.launch(exceptionHandler) {
     withContext(Dispatchers.IO){
          val name = fetchName() //suspend fun
          val surname =  fetchSurname() //suspend fun
     }
     //how to wait response from name and surname to use it in another call?
    //name and surname must be async

 }
private suspend fun fetchName(): Name {
        return withContext(Dispatchers.IO) {
          //db
        }
    }
private suspend fun fetchSurname(): Surname {
        return withContext(Dispatchers.IO) {
         //db
        }
    }

How to wait response from name and surname to use it in another call?

Slava
  • 443
  • 4
  • 12

1 Answers1

2

I assume your code is equivalent to

viewModelScope.launch(Dispatcher.IO)

Therefore everything inside your launch block is executed sequentially, because it is simply one coroutine. It means that any code in the block after

 withContext(Dispatchers.IO){ // Place it in your launch block
      val name = fetchName() //suspend fun
      val surname =  fetchSurname() //suspend fun
 }

will execute only after fetchName and fetchSurname complete. If you want to update some UI after it, for example, you can use

withContext(Dispatchers.Main) { 
   textView1.text = name  
   textView2.text = surname
}

If you want to use it as a property in the view model consider using Flow

UPD: For your specific case

viewModelScope.launch(exceptionHandler) {
    withContext(Dispatchers.IO){
        val name = fetchName() //suspend fun
        val surname =  fetchSurname() //suspend fun

        apiCall(name, surname) // it will execute only after name and surname are fetched
    }
}
Steyrix
  • 2,796
  • 1
  • 9
  • 23
  • yes but how can I get name and surname from this block? – Slava Mar 15 '23 at 12:28
  • 1
    @Slava updated my answer. Depends on how you want to use these values – Steyrix Mar 15 '23 at 12:33
  • I need to use them in api call, not for UI – Slava Mar 15 '23 at 12:34
  • 1
    @Slava you can make an API call right inside the `launch` block after `fetch` calls – Steyrix Mar 15 '23 at 12:35
  • like this? var name: Name var surname: Surname viewModelScope.launch(exceptionHandler) { withContext(Dispatchers.IO){ name = fetchName() surname = fetchSurname() } call(name, surname) } – Slava Mar 15 '23 at 12:37
  • 1
    @Slava I updated my answer once again. There is no need to create global variables for them – Steyrix Mar 15 '23 at 12:39
  • 1
    Also see this question on how to wait for coroutines completion https://stackoverflow.com/questions/59491707/how-to-wait-for-end-of-a-coroutine – Steyrix Mar 15 '23 at 12:39
  • Is fetchName() and fetchSurname async ? – Slava Mar 15 '23 at 12:39
  • 1
    @Slava they are async in relation to UI. It will not freeze UI or other coroutine. They are also async in relation to each other since `Dispatchers.IO` is probably using thread pool under the hood. – Steyrix Mar 15 '23 at 12:40
  • They aren't async to each other because they are called in sequence in the same coroutine (although they might be executed on different threads from the thread pool). `fetchSurname()` will not be called until the preceding line with `fetchName()` returns. Suspend functions are truly synchronous functions. It is only the coroutine as a whole that is asynchronous. – Tenfour04 Mar 15 '23 at 13:12
  • @Tenfour04 as always you have corrected me :) thanks, I actually was thinking about other IO coroutine while was writing that – Steyrix Mar 15 '23 at 14:01