20 Pertanyaan Wawancara Jetpack Compose Teratas di Tahun 2026

20 pertanyaan wawancara Jetpack Compose yang paling sering ditanyakan: recomposition, state management, navigation, performa, dan pola arsitektur dengan contoh kode lengkap.

Pertanyaan wawancara Jetpack Compose untuk developer Android

Wawancara Android modern menuntut penguasaan mendalam terhadap Jetpack Compose. Toolkit deklaratif ini telah menjadi standar industri, menggantikan pendekatan XML tradisional. Panduan ini mencakup 20 pertanyaan yang paling sering diajukan, mencakup dasar-dasar hingga pola arsitektur lanjutan.

Tips Persiapan

Pewawancara tidak hanya menguji pengetahuan sintaks. Kemampuan menjelaskan mekanisme internal seperti recomposition dan smart recomposition menjadi pembeda utama antara kandidat yang menghafal dan yang benar-benar memahami framework.

Dasar-Dasar Jetpack Compose

1. Apa perbedaan antara Jetpack Compose dan XML tradisional?

Jetpack Compose menggunakan pendekatan deklaratif: UI dideskripsikan sebagai fungsi dari state. Ketika state berubah, framework secara otomatis menghitung ulang bagian UI yang terpengaruh. XML menggunakan pendekatan imperatif: developer harus secara manual memanipulasi view melalui findViewById dan setter.

compose_vs_xml.ktkotlin
// Compose: declarative - UI is a function of state
@Composable
fun Greeting(name: String) {
    // UI automatically updates when name changes
    Text(text = "Hello, $name!")
}

// XML equivalent requires:
// 1. Layout XML file
// 2. findViewById in Activity
// 3. Manual setText call
// textView.text = "Hello, $name!"

Keunggulan Compose meliputi: eliminasi boilerplate, preview langsung di IDE, type safety penuh dengan Kotlin, dan composability yang lebih natural dibandingkan inheritance pada View.

2. Apa itu recomposition dan bagaimana cara kerjanya?

Recomposition adalah proses di mana Compose memanggil ulang fungsi composable ketika state yang dibacanya berubah. Framework melakukan smart recomposition: hanya composable yang membaca state yang berubah yang akan dipanggil ulang, bukan seluruh tree.

recomposition_example.ktkotlin
@Composable
fun Counter() {
    // When count changes, only this composable recomposes
    var count by remember { mutableStateOf(0) }

    Column {
        // This Text recomposes when count changes
        Text(text = "Count: $count")

        // This Button also recomposes (same scope)
        Button(onClick = { count++ }) {
            Text("Increment")
        }
    }
}

// This composable does NOT recompose when count changes
@Composable
fun StaticHeader() {
    Text(text = "This never recomposes due to Counter")
}

Recomposition bersifat optimistis dan dapat dibatalkan. Compose dapat memulai recomposition, membatalkannya jika state berubah lagi, dan memulai ulang dengan state terbaru.

3. Apa perbedaan antara remember dan rememberSaveable?

remember menyimpan nilai selama composable berada dalam composition. Nilai hilang saat configuration change (rotasi layar). rememberSaveable menyimpan nilai melewati configuration change menggunakan mekanisme Bundle Android.

remember_vs_saveable.ktkotlin
@Composable
fun SearchBar() {
    // Lost on configuration change (rotation)
    var query by remember { mutableStateOf("") }

    // Survives configuration change
    var savedQuery by rememberSaveable { mutableStateOf("") }

    TextField(
        value = savedQuery,
        onValueChange = { savedQuery = it },
        placeholder = { Text("Search...") }
    )
}

Gunakan remember untuk state sementara yang tidak perlu bertahan (animasi, state hover). Gunakan rememberSaveable untuk input pengguna dan state navigasi yang harus bertahan melewati rotasi layar.

4. Bagaimana Compose menangani siklus hidup composable?

Setiap composable memiliki tiga fase: masuk composition (pertama kali dipanggil), recomposition (dipanggil ulang saat state berubah), dan keluar composition (dihapus dari tree). Lifecycle ini berbeda dari Activity/Fragment lifecycle.

composable_lifecycle.ktkotlin
@Composable
fun UserProfile(userId: String) {
    // Enters composition: effect starts
    // Recomposition: effect restarts if userId changes
    // Leaves composition: effect is cancelled
    LaunchedEffect(userId) {
        // Coroutine tied to this composable's lifecycle
        val user = repository.getUser(userId)
    }

    // DisposableEffect for cleanup
    DisposableEffect(Unit) {
        val listener = database.addListener { /* ... */ }
        onDispose {
            // Called when leaving composition
            listener.remove()
        }
    }
}

Memahami lifecycle ini krusial untuk mengelola side effect dan menghindari memory leak.

State Management

5. Apa itu state hoisting dan mengapa penting?

State hoisting adalah pola memindahkan state ke caller composable. Composable yang menerima state menjadi stateless dan lebih mudah diuji serta di-reuse. State diangkat ke level terendah yang mencakup semua consumer.

state_hoisting.ktkotlin
// Stateless: receives state, emits events
@Composable
fun EmailInput(
    email: String,
    onEmailChange: (String) -> Unit,
    modifier: Modifier = Modifier
) {
    TextField(
        value = email,
        onValueChange = onEmailChange,
        label = { Text("Email") },
        modifier = modifier
    )
}

// Stateful: owns and manages state
@Composable
fun LoginScreen() {
    var email by rememberSaveable { mutableStateOf("") }
    var password by rememberSaveable { mutableStateOf("") }

    Column {
        EmailInput(
            email = email,
            onEmailChange = { email = it }
        )
        PasswordInput(
            password = password,
            onPasswordChange = { password = it }
        )
    }
}

Pola ini mengikuti prinsip unidirectional data flow: state mengalir ke bawah, event mengalir ke atas.

6. Kapan menggunakan derivedStateOf?

derivedStateOf menciptakan state yang dihitung dari state lain, dan hanya memicu recomposition ketika hasil perhitungan berubah. Berguna untuk menghindari recomposition yang tidak perlu.

derived_state.ktkotlin
@Composable
fun ShoppingCart(items: List<CartItem>) {
    // Without derivedStateOf: recomposes on EVERY list change
    // val total = items.sumOf { it.price }

    // With derivedStateOf: recomposes only when total changes
    val total by remember(items) {
        derivedStateOf { items.sumOf { it.price } }
    }

    // Only recomposes when hasDiscount value changes
    val hasDiscount by remember(total) {
        derivedStateOf { total > 100.0 }
    }

    Text("Total: $$total")
    if (hasDiscount) {
        Text("Discount applied!")
    }
}

Gunakan derivedStateOf ketika state sumber sering berubah namun hasil turunannya jarang berubah. Jangan gunakan untuk transformasi sederhana yang selalu menghasilkan nilai berbeda.

7. Bagaimana perbedaan StateFlow dengan Compose State?

StateFlow berasal dari Kotlin coroutines dan bersifat platform-agnostic. MutableState dari Compose terintegrasi langsung dengan sistem recomposition. Keduanya saling melengkapi dalam arsitektur modern.

stateflow_vs_compose_state.ktkotlin
// ViewModel with StateFlow
class UserViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(UserUiState())
    val uiState: StateFlow<UserUiState> = _uiState.asStateFlow()

    fun updateName(name: String) {
        _uiState.update { it.copy(name = name) }
    }
}

data class UserUiState(
    val name: String = "",
    val isLoading: Boolean = false
)

// Composable collecting StateFlow
@Composable
fun UserScreen(viewModel: UserViewModel = viewModel()) {
    // collectAsState bridges StateFlow to Compose State
    val uiState by viewModel.uiState.collectAsState()

    if (uiState.isLoading) {
        CircularProgressIndicator()
    } else {
        Text(uiState.name)
    }
}

Gunakan StateFlow di ViewModel untuk logika bisnis. Gunakan MutableState untuk state UI lokal dalam composable.

Mulai berlatih!

Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.

Side Effect

8. Apa saja Side Effect API utama di Compose?

Compose menyediakan beberapa API untuk menjalankan operasi yang memiliki efek samping di luar scope composable: LaunchedEffect, DisposableEffect, SideEffect, dan rememberCoroutineScope.

side_effects.ktkotlin
@Composable
fun AnalyticsScreen(screenName: String) {
    // LaunchedEffect: runs suspend function, restarts on key change
    LaunchedEffect(screenName) {
        analytics.logScreenView(screenName)
    }

    // DisposableEffect: setup + cleanup
    DisposableEffect(Unit) {
        val observer = LifecycleEventObserver { _, event ->
            if (event == Lifecycle.Event.ON_RESUME) {
                analytics.logResume()
            }
        }
        lifecycle.addObserver(observer)
        onDispose {
            lifecycle.removeObserver(observer)
        }
    }

    // SideEffect: runs on every successful recomposition
    SideEffect {
        // Update non-Compose state
        analyticsHelper.setCurrentScreen(screenName)
    }
}

@Composable
fun ActionButton() {
    // rememberCoroutineScope: for event-driven coroutines
    val scope = rememberCoroutineScope()

    Button(onClick = {
        scope.launch {
            // Cannot use LaunchedEffect here (not composable context)
            performAction()
        }
    }) {
        Text("Execute")
    }
}

Aturannya: LaunchedEffect untuk operasi yang terkait lifecycle composable, rememberCoroutineScope untuk operasi yang dipicu event pengguna.

9. Bagaimana cara mengelola coroutine di dalam Compose?

Coroutine dalam Compose dikelola melalui scope yang terikat pada lifecycle composable. LaunchedEffect membatalkan coroutine ketika composable keluar dari composition atau key berubah.

coroutines_in_compose.ktkotlin
@Composable
fun SearchScreen(query: String) {
    var results by remember { mutableStateOf<List<Result>>(emptyList()) }

    // Debounced search: cancels previous on new query
    LaunchedEffect(query) {
        delay(300) // debounce
        results = searchRepository.search(query)
    }
}

@Composable
fun InfiniteAnimation() {
    val infiniteTransition = rememberInfiniteTransition(label = "pulse")
    val alpha by infiniteTransition.animateFloat(
        initialValue = 0.3f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            animation = tween(1000),
            repeatMode = RepeatMode.Reverse
        ),
        label = "alpha"
    )

    Box(
        modifier = Modifier
            .size(100.dp)
            .alpha(alpha)
            .background(Color.Blue)
    )
}

Jangan pernah meluncurkan coroutine di dalam body composable tanpa side effect API. Hal ini menyebabkan coroutine baru diluncurkan setiap recomposition.

Layout

10. Bagaimana cara kerja LazyColumn dan optimasinya?

LazyColumn hanya meng-compose dan me-layout item yang terlihat di layar, analog dengan RecyclerView. Parameter key krusial untuk performa karena membantu Compose mengidentifikasi item secara unik.

lazy_column.ktkotlin
@Composable
fun UserList(users: List<User>) {
    LazyColumn(
        contentPadding = PaddingValues(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(
            items = users,
            // Key helps Compose track items across changes
            key = { user -> user.id }
        ) { user ->
            UserCard(user = user)
        }
    }
}

// Optimized with remember and stable types
@Composable
fun UserCard(user: User) {
    // Skipped during recomposition if user hasn't changed
    Card {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(text = user.name, style = MaterialTheme.typography.titleMedium)
            Text(text = user.email, style = MaterialTheme.typography.bodyMedium)
        }
    }
}

Hindari operasi berat di dalam lambda items. Gunakan remember untuk komputasi yang mahal dan pastikan data class digunakan agar Compose dapat melakukan equality check dengan benar.

11. Bagaimana cara membuat custom Layout di Compose?

Custom Layout memungkinkan kontrol penuh terhadap pengukuran dan penempatan child. Proses ini melibatkan dua fase: measure (mengukur setiap child) dan place (menempatkan child di posisi yang tepat).

custom_layout.ktkotlin
@Composable
fun StaggeredGrid(
    modifier: Modifier = Modifier,
    columns: Int = 2,
    content: @Composable () -> Unit
) {
    Layout(
        content = content,
        modifier = modifier
    ) { measurables, constraints ->
        val columnWidth = constraints.maxWidth / columns
        val itemConstraints = constraints.copy(
            minWidth = columnWidth,
            maxWidth = columnWidth
        )

        // Measure phase
        val placeables = measurables.map { it.measure(itemConstraints) }

        // Track height per column
        val columnHeights = IntArray(columns)
        val positions = placeables.map { placeable ->
            val col = columnHeights.indexOfMin()
            val position = IntOffset(col * columnWidth, columnHeights[col])
            columnHeights[col] += placeable.height
            position
        }

        val height = columnHeights.max()

        // Place phase
        layout(constraints.maxWidth, height) {
            placeables.forEachIndexed { index, placeable ->
                placeable.placeRelative(positions[index])
            }
        }
    }
}

Custom Layout sebaiknya digunakan ketika Row, Column, dan Box tidak cukup memenuhi kebutuhan. Untuk kasus yang lebih sederhana, Modifier.layout sudah memadai.

12. Bagaimana cara menggunakan MaterialTheme di Compose?

MaterialTheme menyediakan sistem desain yang konsisten melalui tiga pilar: color scheme, typography, dan shapes. Material 3 (Material You) mendukung dynamic color berdasarkan wallpaper pengguna.

material_theme.ktkotlin
// Custom theme definition
@Composable
fun AppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colorScheme = if (darkTheme) {
        darkColorScheme(
            primary = Color(0xFFBB86FC),
            secondary = Color(0xFF03DAC6),
            background = Color(0xFF121212)
        )
    } else {
        lightColorScheme(
            primary = Color(0xFF6200EE),
            secondary = Color(0xFF03DAC6),
            background = Color(0xFFFFFFFF)
        )
    }

    MaterialTheme(
        colorScheme = colorScheme,
        typography = AppTypography,
        shapes = AppShapes,
        content = content
    )
}

// Usage in composables
@Composable
fun ThemedButton() {
    Button(
        onClick = { },
        colors = ButtonDefaults.buttonColors(
            containerColor = MaterialTheme.colorScheme.primary
        )
    ) {
        Text(
            text = "Themed",
            style = MaterialTheme.typography.labelLarge
        )
    }
}

Selalu gunakan token dari MaterialTheme daripada hardcode warna atau ukuran font. Ini memastikan konsistensi dan memudahkan implementasi dark mode.

13. Bagaimana cara mengimplementasikan navigasi dengan NavHost?

NavHost dari library Navigation Compose mengelola back stack dan transisi antar layar. Setiap destinasi didefinisikan sebagai composable dengan route unik.

navigation.ktkotlin
@Composable
fun AppNavigation() {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = "home"
    ) {
        composable("home") {
            HomeScreen(
                onNavigateToDetail = { id ->
                    navController.navigate("detail/$id")
                }
            )
        }

        composable(
            route = "detail/{itemId}",
            arguments = listOf(
                navArgument("itemId") { type = NavType.StringType }
            )
        ) { backStackEntry ->
            val itemId = backStackEntry.arguments?.getString("itemId")
            DetailScreen(itemId = itemId)
        }

        composable("settings") {
            SettingsScreen(
                onBack = { navController.popBackStack() }
            )
        }
    }
}

Jangan pernah meneruskan navController langsung ke composable anak. Gunakan callback lambda agar composable tetap testable dan tidak bergantung pada navigasi.

14. Bagaimana cara mengirim data antar layar di Compose?

Data sederhana dikirim melalui argumen route. Untuk objek kompleks, gunakan savedStateHandle dari ViewModel atau shared ViewModel dengan scope navigation graph.

passing_data.ktkotlin
// Simple arguments via route
navController.navigate("detail/${item.id}")

// Complex data via savedStateHandle
class DetailViewModel(
    savedStateHandle: SavedStateHandle
) : ViewModel() {
    val itemId: String = checkNotNull(savedStateHandle["itemId"])

    // Or pass result back to previous screen
    fun setResult(result: String) {
        savedStateHandle["result"] = result
    }
}

// Reading result in previous screen
@Composable
fun ListScreen(navController: NavController) {
    val result = navController.currentBackStackEntry
        ?.savedStateHandle
        ?.getStateFlow<String>("result", "")
        ?.collectAsState()

    // Use result
}

// Type-safe navigation (recommended)
@Serializable
data class DetailRoute(val itemId: String)

// In NavHost
composable<DetailRoute> { backStackEntry ->
    val route = backStackEntry.toRoute<DetailRoute>()
    DetailScreen(itemId = route.itemId)
}

Hindari mengirim objek besar melalui argumen navigasi. Kirim hanya identifier, lalu muat data lengkap di ViewModel layar tujuan.

Performa

15. Bagaimana cara mencegah recomposition yang tidak perlu?

Recomposition yang berlebihan menurunkan performa. Strategi utama: gunakan stable types, lambda stabilization, dan Compose compiler reports untuk mengidentifikasi masalah.

preventing_recomposition.ktkotlin
// Stable data class - Compose can skip recomposition
@Immutable
data class UserData(
    val id: String,
    val name: String,
    val avatarUrl: String
)

// Lambda stabilization with remember
@Composable
fun ParentScreen(viewModel: MyViewModel = viewModel()) {
    // Without remember: new lambda instance on every recomposition
    // UserList(onItemClick = { id -> viewModel.selectItem(id) })

    // With remember: stable lambda reference
    val onItemClick = remember<(String) -> Unit> {
        { id -> viewModel.selectItem(id) }
    }

    UserList(onItemClick = onItemClick)
}

// Using key to control recomposition scope
@Composable
fun ItemList(items: List<Item>) {
    LazyColumn {
        items(items, key = { it.id }) { item ->
            // Each item recomposes independently
            key(item.id) {
                ItemRow(item = item)
            }
        }
    }
}

Aktifkan Compose compiler metrics (-P plugin:...metricsDestination) untuk mengidentifikasi composable yang tidak stabil.

16. Bagaimana cara melakukan profiling aplikasi Compose?

Android Studio menyediakan Layout Inspector yang menampilkan recomposition count secara real-time. Compose juga menyediakan modifier khusus untuk debugging.

profiling.ktkotlin
// Recomposition counter (debug only)
@Composable
fun DebugRecomposition(tag: String) {
    if (BuildConfig.DEBUG) {
        val recompositionCount = remember { mutableIntStateOf(0) }
        SideEffect {
            recompositionCount.intValue++
        }
        Log.d("Recomposition", "$tag: ${recompositionCount.intValue}")
    }
}

// Performance tracing
@Composable
fun TracedScreen() {
    trace("TracedScreen") {
        // Content here is measured in system trace
        HeavyContent()
    }
}

// Baseline profiles for startup optimization
@ExperimentalBaselineProfilesApi
class BaselineProfileGenerator {
    @get:Rule
    val rule = BaselineProfileRule()

    @Test
    fun generateProfile() {
        rule.collect("com.example.app") {
            startActivityAndWait()
            // Navigate through critical user flows
        }
    }
}

Gunakan Layout Inspector di Android Studio untuk memonitor recomposition count. Composable dengan count tinggi tanpa perubahan visual mengindikasikan masalah performa.

17. Mengapa urutan Modifier penting?

Modifier di Compose diterapkan secara berurutan dari luar ke dalam. Urutan yang berbeda menghasilkan hasil visual yang berbeda. Kesalahan urutan Modifier adalah sumber bug UI yang umum.

modifier_order.ktkotlin
@Composable
fun ModifierOrderDemo() {
    // Order 1: padding THEN background
    // Background covers padded area
    Box(
        modifier = Modifier
            .padding(16.dp)
            .background(Color.Red)
            .size(100.dp)
    )

    // Order 2: background THEN padding
    // Background extends to full size, padding is inside
    Box(
        modifier = Modifier
            .background(Color.Blue)
            .padding(16.dp)
            .size(100.dp)
    )

    // Clickable area depends on order
    Box(
        modifier = Modifier
            .padding(16.dp)        // Padding outside clickable
            .clickable { }          // Click area
            .padding(8.dp)          // Padding inside clickable
            .background(Color.Green)
    )
}

Aturan praktis: baca chain Modifier dari atas ke bawah sebagai lapisan luar ke dalam. padding sebelum background menambahkan ruang di luar background, sedangkan setelahnya menambahkan ruang di dalam.

Kesalahan Umum

Menempatkan clickable setelah padding membuat area padding tidak dapat diklik. Untuk area sentuh yang lebih besar, tempatkan clickable sebelum padding.

Arsitektur

18. Bagaimana pola ViewModel + UiState bekerja dengan Compose?

Pola ini memisahkan logika bisnis (ViewModel) dari presentasi (Composable). ViewModel mengekspos satu StateFlow<UiState> yang merepresentasikan keseluruhan state layar.

viewmodel_uistate.ktkotlin
// Sealed interface for complete state representation
sealed interface HomeUiState {
    data object Loading : HomeUiState
    data class Success(
        val articles: List<Article>,
        val isRefreshing: Boolean = false
    ) : HomeUiState
    data class Error(val message: String) : HomeUiState
}

class HomeViewModel(
    private val repository: ArticleRepository
) : ViewModel() {
    val uiState: StateFlow<HomeUiState> = repository
        .getArticles()
        .map<List<Article>, HomeUiState> { HomeUiState.Success(it) }
        .catch { emit(HomeUiState.Error(it.message ?: "Unknown error")) }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = HomeUiState.Loading
        )

    fun refresh() {
        viewModelScope.launch {
            // Update state to show refreshing
            repository.refresh()
        }
    }
}

// Composable consumes UiState
@Composable
fun HomeScreen(viewModel: HomeViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsState()

    when (val state = uiState) {
        is HomeUiState.Loading -> LoadingIndicator()
        is HomeUiState.Success -> ArticleList(
            articles = state.articles,
            onRefresh = viewModel::refresh
        )
        is HomeUiState.Error -> ErrorMessage(state.message)
    }
}

Gunakan sealed interface untuk UiState agar Compose dapat melakukan exhaustive when check. WhileSubscribed(5000) menghentikan collection saat tidak ada subscriber, menghemat resource.

19. Bagaimana cara menguji composable?

Compose menyediakan ComposeTestRule untuk pengujian UI. Test ditulis menggunakan semantic tree, bukan implementasi visual.

compose_testing.ktkotlin
class LoginScreenTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun loginButton_disabledWhenFieldsEmpty() {
        composeTestRule.setContent {
            LoginScreen()
        }

        // Find by test tag
        composeTestRule
            .onNodeWithTag("loginButton")
            .assertIsNotEnabled()
    }

    @Test
    fun loginButton_enabledWhenFieldsFilled() {
        composeTestRule.setContent {
            LoginScreen()
        }

        // Type in fields
        composeTestRule
            .onNodeWithTag("emailField")
            .performTextInput("test@example.com")

        composeTestRule
            .onNodeWithTag("passwordField")
            .performTextInput("password123")

        // Verify button is enabled
        composeTestRule
            .onNodeWithTag("loginButton")
            .assertIsEnabled()
    }

    @Test
    fun errorMessage_displayedOnFailure() {
        composeTestRule.setContent {
            LoginScreen()
        }

        // Verify error message appears
        composeTestRule
            .onNodeWithText("Invalid credentials")
            .assertExists()
    }
}

Gunakan testTag di Modifier untuk memudahkan pencarian node. Hindari pengujian berdasarkan posisi visual karena rapuh terhadap perubahan layout.

20. Bagaimana cara mengintegrasikan Compose dengan View XML yang sudah ada?

Migrasi bertahap dari XML ke Compose dimungkinkan melalui ComposeView (Compose di dalam XML) dan AndroidView (XML di dalam Compose). Strategi ini memungkinkan adopsi Compose tanpa menulis ulang seluruh aplikasi.

interop.ktkotlin
// Compose inside XML layout
class ExistingFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return ComposeView(requireContext()).apply {
            setViewCompositionStrategy(
                ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
            )
            setContent {
                AppTheme {
                    NewComposeFeature()
                }
            }
        }
    }
}

// XML View inside Compose
@Composable
fun LegacyMapView() {
    AndroidView(
        factory = { context ->
            // Create traditional Android View
            MapView(context).apply {
                // Configure the view
                onCreate(Bundle())
            }
        },
        update = { mapView ->
            // Update view when state changes
            mapView.getMapAsync { map ->
                map.moveCamera(CameraUpdateFactory.newLatLng(location))
            }
        },
        onRelease = { mapView ->
            // Cleanup when leaving composition
            mapView.onDestroy()
        }
    )
}

Strategi migrasi yang direkomendasikan: mulai dengan layar baru menggunakan Compose, lalu migrasikan layar yang sudah ada secara bertahap dari leaf composable ke atas.

Kesimpulan

Ke-20 pertanyaan ini mencakup aspek-aspek krusial wawancara Jetpack Compose: dari dasar-dasar deklaratif hingga pola arsitektur production-ready. Kunci keberhasilan terletak pada pemahaman mendalam terhadap mekanisme recomposition, pengelolaan state yang tepat, dan pengalaman praktis membangun aplikasi nyata.

Checklist Persiapan

  • Kuasai perbedaan Compose deklaratif vs XML imperatif
  • Pahami mekanisme recomposition dan smart recomposition
  • Latih state hoisting dan unidirectional data flow
  • Implementasikan side effect dengan benar (LaunchedEffect, DisposableEffect)
  • Optimalkan LazyColumn dengan key dan stable types
  • Kuasai pola ViewModel + UiState dengan sealed interface
  • Tulis compose test menggunakan semantic tree
  • Pahami interop Compose-XML untuk migrasi bertahap

Mulai berlatih!

Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.

Praktek langsung dengan proyek nyata tetap menjadi metode paling efektif untuk menguasai konsep-konsep ini. Setiap pertanyaan yang dibahas dalam panduan ini layak dieksplorasi lebih dalam dengan implementasi kode yang sesungguhnya.

Tag

#jetpack compose
#android
#interview
#kotlin
#ui

Bagikan

Artikel terkait