Interview Questions and Answers (2025 Edition)
1. What is Jetpack Compose and why was it introduced?
Answer:
Jetpack Compose is Android’s modern declarative UI toolkit, allowing developers to build interfaces by declaring UI components in Kotlin. It replaces the imperative XML + View system, enabling:
- Conciseness: Less boilerplate compared to XML layouts.
- Reactivity: UI automatically updates when underlying state changes.
- Kotlin-first: Leverages Kotlin language features (lambdas, coroutines).
- Interoperability: Works alongside existing Views for gradual migration.
2. Explain the concept of “composable functions.”
Answer:
A composable function is a Kotlin function annotated with @Composable. It describes a piece of UI and can call other composables. Key points:
- Stateless by default: Only relies on parameters or ambient state.
- Recomposition: When inputs change, Compose re-invokes the function to update UI.
- Lightweight: No overhead of creating new View instances.
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
3. How does state handling work in Compose?
- remember { mutableStateOf(...) }: Holds state within a composition.
- rememberSaveable { mutableStateOf(...) }: Persists across configuration changes.
- State<T> flows into recomposition: When state changes, dependent composables recompose.
4. What is recomposition, and how can you optimize it?
- key scopes: Group lists or looping UI to minimize invalidation.
- derivedStateOf: Compute expensive values only when dependencies change.
- MutableState granularity: Prefer small, focused state variables.
- SideEffect APIs: Use LaunchedEffect, DisposableEffect for non-UI work.
5. Describe LaunchedEffect, SideEffect, and DisposableEffect.
- LaunchedEffect(key1, ...): Runs a suspend block when keys change; cancels on recomposition. Ideal for coroutines.
- SideEffect { }: Runs after every successful recomposition. Good for non-suspend callbacks (e.g., analytics).
- DisposableEffect(key1, ...): Provides onDispose { }, useful for cleanup (e.g., unregister listeners).
6. How do you build lists in Jetpack Compose?
val myList = listOf(
Items(
id = 1,
title = "First Title"
)
)
data class Items(
val id : Int,
val title: String
)
LazyColumn {
items(items = myList, key = { it.id }) { item ->
Text(item.title)
}
}
- itemsIndexed: Provides index.
- keys: Helps Compose identify items for animations and minimal recomposition.
7. Explain theming and material components in Compose.
- MaterialTheme: Wrap your app and access colors, typography, shapes.
- Dynamic theming: Support dark/light mode via isSystemInDarkTheme().
- Custom themes: Override material defaults by supplying your own palettes.
8. How can you interop between Views and Compose?
- Compose in Views: Use ComposeView in XML or an Android ViewGroup.
- Views in Compose: Use AndroidView(factory = { context -> MyLegacyView(context) }) to host existing Views.
9. What is rememberCoroutineScope() used for?
10. How do you handle navigation in Compose?
@Composable
fun MyNav() {
val navController = rememberNavController()
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen(navController) }
composable("details/{itemId}") { backStackEntry ->
DetailsScreen(backStackEntry.arguments?.getString("itemId"))
}
}
}
11. Explain snapshot flow and how to collect it.
12. What are “slots” or slot APIs in Compose?
@Composable
fun MyContainer(content: @Composable () -> Unit) {
Column { content() }
}
13. How do you implement animations in Compose?
- High-level: animate*AsState (e.g., animateDpAsState) for simple property changes.
- Low-level: updateTransition for multi-property or sequential animations.
- AnimatedVisibility: Show/hide with built-in animations.
14. Describe recomposition scope and stability.
15. What testing tools are available for Compose?
- Unit tests: Call composables and verify UI state via composeTestRule.setContent {}.
- UI tests: Use Espresso-like APIs (onNodeWithText, performClick).
- Snapshot testing: Capture golden images for regressions.
16. How do you load images efficiently in Compose?
Image(
painter = painterResource(id = story.imageRes),
contentDescription = story.title,
contentScale = ContentScale.Crop,
modifier = Modifier
.fillMaxWidth()
.height(120.dp)
.clip(RoundedCornerShape(8.dp))
)
17. Explain composition locals.
val LocalUser = compositionLocalOf<User> { error("No user provided") }
CompositionLocalProvider(LocalUser provides currentUser) {
// children can read LocalUser.current
}18. How do you manage side‑effects when a composable leaves the composition?
DisposableEffect(Unit) {
val listener = registerListener()
onDispose { unregisterListener(listener) }
}19. What are best practices for modularizing a Compose app?
- Feature-based modules: Keep UI, ViewModels, and data within feature boundaries.
- Use interfaces: Expose screen navigation through contracts.
- Shared UI library: Extract common components (buttons, cards).
- Design tokens: Centralize colors, typography in a theme module.
