Home > Enterprise >  How to wait for Network response and then move(execute code) further after getting response in jetpa
How to wait for Network response and then move(execute code) further after getting response in jetpa

Time:10-12

I am trying to achieve a functionality where my Complete profile page will check all the use cases for each field.

Every other field works fine with view-model and uses-cases but I am facing a problem while trying to check if username all ready exists or not in Firebase.

Use-Case for User Name.

class ValidateUserName() {

private var userAlways by Delegates.notNull<Boolean>()

@OptIn(DelicateCoroutinesApi::class)
suspend fun execute(userName: String): ValidationResult {
    return ValidationResult(
        successful = false,
        errorMessage = "UserName Can't be empty"
    )
}

suspend fun query(userName: String): ValidationResult {
    val successful = getResult(userName)
    if (successful) {
        return ValidationResult(
            successful = false,
            errorMessage = "UserName already Exists \nPlease try another Username"
        )
    } else {
        return ValidationResult(
            successful = true
        )
    }
}

suspend fun getResult(userName: String): Boolean {
    var x = 0
    val readUserNameQuery = Firebase.firestore.collection("users")
    readUserNameQuery.whereEqualTo("username", userName).get().addOnSuccessListener {
        Log.e("RONALDO", "HERE I AM HERE :- "   it.toObjects<Any>().size)
        x = it.toObjects<Any>().size
    }.await()
    delay(2000L)
    return x > 0
}

}

ViewModel (Caller)

class CompleteProfileViewModel(
private val validateEmail : ValidateEmail = ValidateEmail(),
private val validateFirstName : ValidateFirstName = ValidateFirstName(),
private val validateLastName: ValidateLastName = ValidateLastName(),
private val validateUserName: ValidateUserName = ValidateUserName()

) : ViewModel() { var state by mutableStateOf(CompleteProfileState())

private val validationEventChannel = Channel<ValidationEvent>()
val validationEvents = validationEventChannel.receiveAsFlow()

fun onEvent(event: CompleteProfileEvent ){
    when(event){
        is CompleteProfileEvent.EmailChanged -> {
            state = state.copy(email = event.email)
        // the way to change state is to create(copy) whole new object
        }
        is CompleteProfileEvent.FirstNameChanged -> {
            state = state.copy(firstName = event.firstName)
        }
        is CompleteProfileEvent.LastNameChanged -> {
            state = state.copy(lastName = event.lastName)
        }
        is CompleteProfileEvent.UserNameChanged -> {
            state = state.copy(userName = event.userName)
        }
        is CompleteProfileEvent.Submit -> {
            viewModelScope.launch {
                submitData()
            }
        }
    }
}

private suspend fun submitData() {

    val userNameResult = if (state.userName.isNotBlank()){
        validateUserName.query(state.userName)
    }else{
        validateUserName.execute(state.userName)
    }
    val emailResult = validateEmail.execute(state.email)
    val firstNameResult = validateFirstName.execute(state.firstName)
    val lastNameResult = validateLastName.execute(state.lastName)
    val hasError = listOf(
        userNameResult,
        emailResult,
        firstNameResult,
        lastNameResult
    ).any{
        !it.successful
    }
    if (hasError){
        state = state.copy(
            emailError = emailResult.errorMessage,
            firstNameError = firstNameResult.errorMessage,
            lastNameError = lastNameResult.errorMessage,
            userNameError = userNameResult.errorMessage
        )
        return
    }
    viewModelScope.launch {
        validationEventChannel.send(ValidationEvent.Success)
    }
}
sealed class ValidationEvent{
    object Success : ValidationEvent()
}

}

Sorry for this code is not formatted Correctly

I just want to wait for my Firebase response before moving further. await() is not working in my case. suspend fun getResult(userName: String): Boolean() is returning false and then getting the response.

Can anyone help me with this?

CodePudding user response:

The problem in your code lies in the following lines of code:

readUserNameQuery.whereEqualTo("username", userName).get().addOnSuccessListener {
    Log.e("RONALDO", "HERE I AM HERE :- "   it.toObjects<Any>().size)
    x = it.toObjects<Any>().size
}.await()

Firebase API is asynchronous. Any code that needs data from the database needs to be inside the onSuccess() method, or be called from there. That being said, returning a value from an asynchronous operation as a result of a method doesn't provide the expected result.

await() is not working in my case.

It's because you're calling await() after attaching the listener. If you want to wait for the operation to complete, then you should call await() right after calling get(). It's one or the other:

val size = readUserNameQuery.whereEqualTo("username", userName).get().await().toObjects<Any>().size
Log.e("RONALDO", "HERE I AM HERE :- "   size)
  • Related