0
0
Android Kotlinmobile~20 mins

StateFlow and SharedFlow in Android Kotlin - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Counter with StateFlow and SharedFlow
A simple Android screen that shows a counter value updated using StateFlow and emits one-time events using SharedFlow.
Target UI
-------------------------
| Counter App           |
|-----------------------|
| Count: 0              |
|                       |
| [Increment] [Reset]   |
|                       |
| Event: None           |
-------------------------
Display a count value that updates reactively using StateFlow.
Two buttons: Increment increases count by 1, Reset sets count to 0.
Use SharedFlow to emit one-time events when count reaches multiples of 5.
Show the latest event message below the buttons.
Use Kotlin coroutines and flows properly in ViewModel and Activity.
Starter Code
Android Kotlin
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.viewModels
import androidx.lifecycle.lifecycleScope
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)

        // TODO: Observe StateFlow and SharedFlow from viewModel
        // TODO: Set click listeners for buttons
    }
}

// TODO: Create CounterViewModel with StateFlow and SharedFlow
Task 1
Task 2
Task 3
Task 4
Solution
Android Kotlin
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.

Final Result
Completed Screen
-------------------------
| Counter App           |
|-----------------------|
| Count: 7              |
|                       |
| [Increment] [Reset]   |
|                       |
| Event: Reached multiple|
| of 5: 5               |
-------------------------
Tapping Increment increases the count by 1 and updates the Count text.
When count reaches 5, 10, 15, etc., an event message appears below buttons.
Tapping Reset sets count to 0 and shows 'Counter reset to zero' event.
Stretch Goal
Add a Toast message that shows the event text whenever a new event is emitted.
💡 Hint
Use lifecycleScope to collect events and call Toast.makeText(context, event, Toast.LENGTH_SHORT).show() inside the collector.