For one-shot operations you usually don't need lifecycle management.
If you need a StateFlow I would recommend simply using stateIn() to create a non-lifecycle aware StateFlow that starts immediately and will only be cancelled when the ViewModel is destroyed:
oneShotOperationFlow()
.stateIn(viewModelScope, SharingStarted.Eagerly, Result.Empty)
Alternatively you can use async{} to build a Deferred.
If you really need the one-shot operation to be cancelled when the UI is hidden and restart when the UI reappears but only if it didn't complete before, you can create a Flow operator for that. For example:
fun <T> Flow<T>.flowOnce(): Flow<T> {
var isComplete = false
return flow {
if (!isComplete) {
collect {
emit(it)
}
isComplete = true
}
}
}
Then you can use it in combination with stateIn():
oneShotOperationFlow()
.flowOnce()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(1000L), Result.Empty)