
answers:
- "a()"
- "b()"
- "c()"
- "d()"
correct:
- "b()"
- "c()"
- "d()"
explanation: "When text gets changed, its reader scope gets recomposed. We read text in Column, but Column is an inline function, so it is Card scope, which includes b(), c(), and d()."
- type: "single-answer"
question: "What should be used to store user text input in a form?"
answers:- "remember"
- "retain"
- "rememberSaveable"
- "rememberSerializable"
correct: "rememberSaveable"
explanation: "Use rememberSaveable so user input survives configuration changes; String is Bundle-compatible."
- type: "single-answer"
question: "What should be used to store an OkHttp WebSocket connection? (you don't want it lost in case od configuration changes)"
answers:- "remember"
- "retain"
- "rememberSaveable"
- "rememberSerializable"
correct: "retain"
explanation: "The live socket must remain connected through configuration changes and cannot be saved to a Bundle."
- type: "single-answer"
question: "What should be used to store state observed from StateFlow?"
answers:- "remember"
- "retain"
- "rememberSaveable"
- "rememberSerializable"
correct: "remember"
explanation: "The data can be re-read from the flow after configuration changes; no need to save it in a Bundle."
- type: "single-answer"
question: "What should be used to store scroll state?"
answers:- "remember"
- "retain"
- "rememberSaveable"
- "rememberSerializable"
correct: "rememberSaveable"
explanation: "Scroll position should persist through rotations and is already handled via rememberScrollState."
- type: "single-answer"
question: "What is the right way to defineimageUrl?"
answers:- "val imageUrl = profile.imageUrl"
- "val imageUrl = remember { profile.imageUrl }"
- "val imageUrl = remember(profile) { profile.imageUrl }"
- "val imageUrl = remember(profile.imageUrl) { profile.imageUrl }"
correct: "val imageUrl = profile.imageUrl"
explanation: "Accessingprofile.imageUrlis lightweight; remembering it adds overhead without benefit."
- type: "single-answer"
question: "What is the right way to defineinitials?"
answers:- |
undefined
- |
val (name, surname) = profile.fullName.split(" ")
"${name.first()}${surname.first()}"
}
- |
```kotlin
val initials = remember {
val (name, surname) = profile.fullName.split(" ")
"${name.first()}${surname.first()}"
}
- |
```kotlin
val (name, surname) = profile.fullName.split(" ")
"${name.first()}${surname.first()}"
}
- |
```kotlin
val initials = remember(profile.fullName) {
val (name, surname) = profile.fullName.split(" ")
"${name.first()}${surname.first()}"
}
correct: |
```kotlin
val (name, surname) = profile.fullName.split(" ")
"${name.first()}${surname.first()}"
}
explanation: "Initials require non-trivial operations on strings; remember them to avoid recomputation, keyed by `profile.fullName` which they depend on."
- type: "multiple-answer"
question: |
Which of those types are **unstable** in Compose?
answers:
- "Int"
- "String"
- "List<Int>"
- "State<Int>"
- "StateFlow<Int>"
- "() -> Unit"
- "() -> List<Int>"
- "Comparator<Int>"
- "PersistentList<Int?>"
- "PersistentList<List<Int?>>"
- "StringBuilder"
correct:
- "List<Int>"
- "StateFlow<Int>"
- "PersistentList<List<Int?>>"
- "StringBuilder"
explanation: ""
- type: "multiple-answer"
question: |
Which of those classes are *unstable* in Compose?
answers:
- "data class User(val name: String)"
- "data class User(var name: String)"
- "data class User(val name: String, val tags: Set<String>)"
- "data class User(val nameState: State<String>)"
- "data class User(val nameState: StateFlow<String>)"
- "@Stable data class User(var name: String)"
- "@Immutable data class User(var name: String)"
correct:
- "data class User(var name: String)"
- "data class User(val name: String, val tags: Set<String>)"
- "data class User(val nameState: StateFlow<String>)"
explanation: "`class User(val name: String)` is stable, because it only has stable val properties. `class User(var name: String)` isn’t, because it has var property. `class User(val name: String, val tags: Set<String>)` isn’t because it uses Set, which isn’t stable. `class User(val nameState: State<String>)` is, because State is stable in Compose. `class User(val nameState: StateFlow<String>)` isn’t because StateFlow isn’t stable. `@Stable class User(var name: String)` and `@Immutable class User(var name: String)` are stable, because both @Stable and @Immutable enforce stability."
- type: "multiple-answer"
question: |
```kotlin
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.*
import androidx.compose.ui.*
import androidx.compose.ui.draw.*
import androidx.compose.ui.unit.*
import androidx.compose.ui.window.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.vector.*
import kotlinx.browser.document
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.lazy.grid.*
import androidx.compose.foundation.shape.*
import androidx.compose.ui.text.font.*
import androidx.compose.ui.text.style.*
import androidx.compose.ui.text.input.*
import androidx.lifecycle.compose.*
import androidx.compose.ui.layout.*
//sampleStart
data class UserUiState(
val user: UserUi,
val userSettings: UserSettingsUi,
)
data class UserUi(
val name: String,
val surname: String,
)
data class UserSettingsUi(
val allowNewsletter: Boolean,
)
@Composable
fun UserScreen(viewModel: UserScreenViewModel = injectViewModel()) {
val uiState: UserUi by viewModel.uiState.collectAsStateWithLifecycle()
UserCard(uiState.user)
UserSettings(uiState.userSettings, { viewModel.toggleAllowNewsletter(it) })
}
@Composable
fun UserCard(user: UserUi) {
Text(user.name)
Text(user.surname)
}
@Composable
fun UserSettings(userSettings: UserSettingsUi, toggleAllowNewsletter: (Boolean) -> Unit) {
Switch(
checked = userSettings.allowNewsletter,
onCheckedChange = toggleAllowNewsletter
)
}
//sampleEnd
What will recompose if on the view model:
```kotlin
answers:
- "Text that displays name"
- "Text that displays surname"
- "UserCard"
- "UserScreen"
- "Switch"
- "UserSettings, because lambda is used instead of a function reference"
- "UserSettings, because uiState is unstable"
correct:
- "Text that displays name"
- "UserCard"
- "UserScreen"
explanation: "StateFlow with UserUiState is observed where we read it, so in UserScreen, because in UserScreen we call uiState.user and uiState.userSettings. This recomposition propagates to UserCard, because the user inside UserUiState changed, but not to UserSettings. userSettings hasn’t changed, and the lambda expression is stable and memoized by default. Inside UserCard, the first Text gets recomposed, but the second one skips recomposition, because it receives the same value as the previous one."
- 0-3 If you plan to implement Compose applications, you should better learn about stability and recomposition
- 4-6 This is nice, but there is room for improvement
- 7-9 You are doing great, keep it up!
- 10 Nice! You seem to understand recomposition and stability pretty well
- Modifiers (layout, interaction, drawing, transformations)
- MaterialTheme & CompositionLocal setup
- Stability rules (what’s stable vs unstable — and why it matters)
- What actually triggers recomposition
- Delayed state reads & hoistable stable state patterns
📬 Join 20k+ Kotlin developers receiving practical weekly insights
❌ No spam. Unsubscribe anytime.
Get your free cheat sheet → Here