3

I am trying to implement kotlin stateflow, but not able to know the reason why it is not working.

Current output: verificatio 34567

Expected Output: verificatio 34567 verificatio failed

package stateflowDuplicate

import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
val firebasePhoneVerificationListener = FirebaseOTPVerificationOperation1()
val oTPVerificationViewModal = OTPVerificationViewModal1(firebasePhoneVerificationListener)
oTPVerificationViewModal.fail()
}

class OTPVerificationViewModal1(private val firebasePhoneVerificationListener: FirebaseOTPVerificationOperation1) {

init {
    startPhoneNumberVerification()
    setUpListener()
}

 suspend fun fail(){
    firebasePhoneVerificationListener.fail()
}

private fun startPhoneNumberVerification() {
    firebasePhoneVerificationListener.initiatePhoneVerification("34567")
}

private fun setUpListener() {
    runBlocking {
        firebasePhoneVerificationListener.phoneVerificationFailed.collect {
            println("verificatio $it")
        }
    }
}

}

Second class
package stateflowDuplicate

import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.runBlocking

class FirebaseOTPVerificationOperation1 {

private val _phoneVerificationFailed = MutableStateFlow<String?>(null)
val phoneVerificationFailed: StateFlow<String?>
    get() = _phoneVerificationFailed

  fun initiatePhoneVerification(phoneNumber: String) {
         _phoneVerificationFailed.value = phoneNumber
}
 suspend fun fail() {
     delay(200L)
    _phoneVerificationFailed.value = "failed"
}

}

Tried to understand the concept from these links, Link1 Link2

Reprator
  • 2,859
  • 2
  • 32
  • 55

1 Answers1

3

You have to start a new coroutine to call collect because the coroutine will keep collecting values until its Job gets cancelled. Don't use runBlocking builder for that, use launch builder instead:

private fun setUpListener() = launch {
    firebasePhoneVerificationListener.phoneVerificationFailed.collect {
        println("verificatio $it")
    }
}

Now to make it work you need to implement CoroutineScope interface in your class. You can do it like this:

class OTPVerificationViewModal1(
    private val firebasePhoneVerificationListener: FirebaseOTPVerificationOperation1
): CoroutineScope by CoroutineScope(Dispatchers.Default) {
    ...
}

If you run it now you will get this output:

verificatio 34567
verificatio failed
Glenn Sandoval
  • 3,455
  • 1
  • 14
  • 22
  • thanks for the quick response, but can u please tell me why it was not working with viewmodal as coroutinescope is by default exist in that with ktx – Reprator Jun 11 '20 at 12:53
  • Please look into this link, https://stackoverflow.com/questions/62331931/mutablestateflow-is-not-emitting-values-after-1st-time-kotlin-coroutine , the issue is same but it is with viewmodal android – Reprator Jun 12 '20 at 01:36
  • please help me with above linked question, as i have done everything as per current answer here, but still not firing – Reprator Jun 12 '20 at 08:56
  • @Reprator I saw your code but it's hard to keep track since there are parts that are not clear what they do. I would use the Log to see if every method is being called. For example inside `secondCall` method, inside `resendPhoneVerificationCode` method, etc. – Glenn Sandoval Jun 12 '20 at 09:36
  • please go through the question once again, i have updated the question with minimal code, and current and expected output – Reprator Jun 12 '20 at 10:44
  • Is this done in a ViewModel? – IgorGanapolsky Mar 08 '23 at 16:00
  • 1
    @IgorGanapolsky ViewModels have their own coroutine scope (`viewModelScope`). Use that one if you need to launch coroutines. – Glenn Sandoval Mar 08 '23 at 23:40