import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.activity.viewModels
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
private val viewModel: CounterViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val countText = findViewById<TextView>(R.id.countText)
val eventText = findViewById<TextView>(R.id.eventText)
val incrementButton = findViewById<Button>(R.id.incrementButton)
val resetButton = findViewById<Button>(R.id.resetButton)
lifecycleScope.launch {
viewModel.count.collect { value ->
countText.text = "Count: $value"
}
}
lifecycleScope.launch {
viewModel.events.collect { event ->
eventText.text = "Event: $event"
}
}
incrementButton.setOnClickListener {
viewModel.increment()
}
resetButton.setOnClickListener {
viewModel.reset()
}
}
}
class CounterViewModel : ViewModel() {
private val _count = MutableStateFlow(0)
val count = _count.asStateFlow()
private val _events = MutableSharedFlow<String>()
val events = _events.asSharedFlow()
fun increment() {
val newValue = _count.value + 1
_count.value = newValue
if (newValue % 5 == 0) {
viewModelScope.launch {
_events.emit("Reached multiple of 5: $newValue")
}
}
}
fun reset() {
_count.value = 0
viewModelScope.launch {
_events.emit("Counter reset to zero")
}
}
}This app uses StateFlow to hold the current count value. StateFlow always has a current value and updates the UI reactively when the count changes.
We use SharedFlow to send one-time events like messages when the count reaches multiples of 5 or when reset. SharedFlow does not hold a value but emits events that subscribers can react to.
The CounterViewModel manages the state and events. The MainActivity collects these flows and updates the UI accordingly. Buttons call ViewModel functions to change state or emit events.
This separation keeps UI and logic clean and reactive.