Hi, I am using a Channel in my ViewModel to send o...
# compose-android
v
Hi, I am using a Channel in my ViewModel to send one-time events to my Compose UI. However, when collecting the events in my Compose function, the log keeps printing continuously instead of once. Here’s my implementation:
ViewModel:
Copy code
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch

sealed class ProfileAction {
    object OnChangePasswordClick : ProfileAction()
}

class ProfileViewModel : ViewModel() {

    // Define a Channel to send actions
    private val eventChannel = Channel<ProfileAction>()
    val events = eventChannel.receiveAsFlow()

    // Function to send actions to the channel
    fun onAction(action: ProfileAction) {
        viewModelScope.launch {
            Log.e("ProfileViewModel", "onAction: $action") // This prints only once
            eventChannel.send(action)
        }
    }
}
Compose UI:
Copy code
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.compose.runtime.LaunchedEffect
import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun ProfileScreen(profileViewModel: ProfileViewModel = viewModel()) {

    // Collect the events as a state (with lifecycle awareness)
    val events by profileViewModel.events.collectAsStateWithLifecycle(initial = "")

    when (events) {
        is ProfileAction.OnChangePasswordClick -> {
            Log.e("ProfileScreenRoute", "OnChangePasswordClick") // This keeps printing continuously
            updateChangePassword()
        }
    }

    // Button to trigger the action
    Button(onClick = { profileViewModel.onAction(ProfileAction.OnChangePasswordClick) }) {
        Text("Change Password")
    }
}
Issue:
Log.e("ProfileViewModel", "onAction: $action")
in the ViewModel prints only once when an action is sent. • However,
Log.e("ProfileScreenRoute", "OnChangePasswordClick")
in the Compose function keeps printing continuously whenever the UI recomposes. What’s the problem here, and how can I fix it? I believe the issue is that using
collectAsStateWithLifecycle
leads to the state getting recomposed, causing the event to be handled repeatedly. What’s the best way to properly handle one-time events with Compose and a
Channel
without causing continuous recompositions?
c
Check the discussion and the link at the end https://slack-chats.kotlinlang.org/t/11970131/hello-everyone-how-are-you-handling-one-time-events-between- What you are doing is bad practice.
v
Ohh I don't know that is bad practice. Thanks for sharing the link I'll take a look now.
v
Thank you Christian
c