Search code examples
androidandroid-fragmentskotlin-coroutinesandroid-lifecycleandroid-viewmodel

lifecycleScope aware fragment scope coroutine calls viewmodel coroutine scope function even though not called


I have a lifecycle aware fragment scope coroutine function that checks whether a value received from the fragments' parent activity has a certain value. If the value is null a function is called that has viewModelScope.launch coroutine scope to start a count down before showing a dialog to inform the user that the value disables certain app functionalities.
The problem is that the viewModelScope.launch coroutine function is called all the time even though the conditional if statement is not true.

My question is why would a viewModelScope coroutine function be called if it is inside a conditional that is clearly false? I did notice that if I Log an output inside the if conditional it is not logged and if I Log output outside the viewModelScope.launch coroutine it is also not called. So the scoped code runs notwithstanding the value of the conditional.

The workaround for this was to make the viewmodel function a suspend function and remove the viewModelScope.launch coroutine. But why would a function be called that does not meet a conditional. Does coroutines transcend the boundaries of logic?
The lifecycleScope function has the following make up:

viewLifecycleOwner.lifecycleScope.launch {
    viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
        viewModel.status.collectLatest {
            
            binding.contentScanner.tvScannerStatus.text = it
            if (statusCheck(it) == null) {
                viewModel.reactToInactiveScanner(it)  // This function is called even though the condition is false
            }
        }
    }
}

The viewModelScope coroutine:

fun reactToInactiveScanner(s: String) {
    viewModelScope.launch {
        for(i in 1..5) {
            if(isScannerUnavailable(s)) break
            delay(1000L)
        }
        _scannerActive.value = isScannerUnavailable(s)
    }
}

Solution

  • Probably statusCheck(it) is null when you think it is not ooor, since reactToInactiveScanner(s: String) is launching a coroutine in the view model scope and suspending for at least 5 seconds, and given that the viewmodel survives configuration change, doesnt matter what the lifecycle is doing, the coroutine in the viewmodel scope will keep running for 5 seconds.

    try to make the function suspending :

    suspend fun reactToInactiveScanner(s: String) {
            for(i in 1..5) {
                if(isScannerUnavailable(s)) break
                delay(1000L)
            }
            _scannerActive.value = isScannerUnavailable(s)
    }
    

    and launch it in the lifecycle scope, so when the lifecycle stop the coroutine get canncelled and when it starts the coroutine gets launched again