0
0
Android Kotlinmobile~20 mins

SharedFlow for events in Android Kotlin - Mini App: Build & Ship

Choose your learning style9 modes available
Build: EventEmitterScreen
This screen demonstrates how to use SharedFlow to emit and collect one-time events in an Android Kotlin app. It has a button that when clicked emits an event, and a text area that shows the latest event received.
Target UI
-------------------------
| Event Emitter Screen   |
-------------------------
|                       |
| [Emit Event]           |
|                       |
| Last Event:            |
|                       |
|                       |
-------------------------
Use MutableSharedFlow to emit string events when the button is clicked
Collect the SharedFlow in a lifecycle-aware way to update the UI with the latest event
Display the last emitted event below the button
Use Kotlin coroutines and Flow APIs
Ensure events are handled only once and UI updates accordingly
Starter Code
Android Kotlin
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch

class EventEmitterScreen : ComponentActivity() {
    private val _eventFlow = MutableSharedFlow<String>()
    private val eventFlow = _eventFlow.asSharedFlow()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                Surface(modifier = Modifier.padding(16.dp)) {
                    // TODO: Add UI and collect events here
                }
            }
        }
    }
}
Task 1
Task 2
Task 3
Solution
Android Kotlin
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch

class EventEmitterScreen : ComponentActivity() {
    private val _eventFlow = MutableSharedFlow<String>()
    private val eventFlow = _eventFlow.asSharedFlow()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MaterialTheme {
                Surface(modifier = Modifier.padding(16.dp)) {
                    val scope = rememberCoroutineScope()
                    var lastEvent by remember { mutableStateOf("No events yet") }

                    LaunchedEffect(Unit) {
                        eventFlow.collect { event ->
                            lastEvent = event
                        }
                    }

                    Column {
                        Button(onClick = {
                            scope.launch {
                                _eventFlow.emit("Event at " + System.currentTimeMillis())
                            }
                        }) {
                            Text("Emit Event")
                        }
                        Text(text = "Last Event: $lastEvent", modifier = Modifier.padding(top = 16.dp))
                    }
                }
            }
        }
    }
}

This solution uses MutableSharedFlow to emit string events when the button is clicked. The eventFlow is collected inside a LaunchedEffect to update the lastEvent state variable whenever a new event is emitted. The UI shows a button labeled "Emit Event" and below it the last event received. The coroutine scope is used to emit events asynchronously. This setup ensures events are handled only once and the UI updates reactively.

Final Result
Completed Screen
-------------------------
| Event Emitter Screen   |
-------------------------
|                       |
| [Emit Event]           |
|                       |
| Last Event:            |
| Event at 1680000000000 |
|                       |
-------------------------
When the user taps the 'Emit Event' button, a new event string with the current timestamp is emitted.
The text below updates to show the latest event string.
Events are handled one at a time and the UI always shows the most recent event.
Stretch Goal
Add a Snackbar that briefly shows the event message each time an event is emitted.
💡 Hint
Use ScaffoldState and rememberCoroutineScope to show Snackbar inside the button click coroutine.