简体   繁体   中英

How to send the result of viewModelScope.launch{} as the return value of a function?

In the code snippet below, how to get the value of isValid after viewModelScope.launch is finished.

viewModelScope.launch runs at last, inside fun checkCode() . So fun checkCode() is always return false.

fun someListener() {
    if (checkCode() == true) {
        //do something
    }
}

fun checkCode(): Boolean {
    var isValid = false

    viewModelScope.launch(Dispatchers.Main) {
        val response = withContext(Dispatchers.IO) {
            // something do in background
        }
        
        if (response == "someString") {
            isValid = true
            // tried to type "return isValid" but syntax error
        }
    }
    
    // the problem is below statements run before viewModelScope.launch
    if (isValid) return true
    else return false
}

suspend function runs on background thread. To get the result from that function instead of using return use LiveData .

private val _isValid = MutableLiveData<Boolean>()
val isValid: LiveData<Boolean> // To observe the value outside the ViewModel class.
get() = _isValid

...
suspend fun doBackgroundWork() {
   ...
   _isValid.postValue(true)
   ...
}

Now you can update the private value in the background thread and also observe this in the view controller (Fragment/Activity) , do appropriate operations when you get the updated value.

Few different ways to use liveData from Documentation

viewModelScope.launch will always return a Job . So you can't really return a value from it. To gain what you want you can change your code style like below:

fun someListener() {
    viewModelScope.launch {
        if (checkCode() == true) {
            //do something
        }
    }
}

suspend fun checkCode(): Boolean {
    var isValid = false

    val response = withContext(Dispatchers.IO) {
            // something do in background
    }
        
    if (response == "someString") {
        isValid = true
    }
    
    return isValid
}

Make the function a suspend function and run the entire thing in the coroutine, including the function and its return. Since you can't block the main thread while waiting for the coroutine to finish, you need to make it a suspend function so that it can suspend without blocking.

Your end result would look something like this:

fun someListener() {
    viewModelScope.launch(Dispatchers.Main) {
        if (checkCode() == true) {
            //do something
        }
    }
}

suspend fun checkCode(): Boolean {
    val response = withContext(Dispatchers.IO) {
        // something in background
    }
        
    if (response == "someString") {
        return true
    }
    
    return false
}

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