MutableState — status yang dapat diamati dan mekanisme pembaruan di Compose

Penulis: IT Sectr Diterbitkan: 2026-06-28 Waktu membaca: 7 mnt

MutableState — adalah antarmuka di Jetpack Compose yang mewakili wadah untuk nilai yang dapat diamati dan berubah. Ini adalah dasar dari sistem reaktif Compose: setiap kali nilai MutableState berubah melalui setter, Compose Runtime memberi tahu semua komponen pembaca dan memicu rekomposisi. Menurut Google Android Developers, 2026, memahami MutableState adalah wajib untuk bekerja dengan benar dengan status di UI deklaratif.

Poin utama

  • MutableState — antarmuka compose.runtime dengan satu properti value (getter + setter)
  • State — antarmuka induk hanya-baca, MutableState menambahkan kemampuan menulis
  • Rekomposisi dipicu saat pemanggilan setter value dalam siklus snapshot aktif
  • SnapshotMutationPolicy menentukan kapan perubahan dianggap signifikan untuk rekomposisi
  • MutableIntState dan sejenisnya — versi primitif yang dioptimalkan dari MutableState

Apa itu MutableState di Jetpack Compose

MutableState — adalah antarmuka dari paket androidx.compose.runtime yang mendeklarasikan satu properti: override var value: T. Getter mengembalikan nilai saat ini, setter menulis yang baru dan memberi tahu Compose Runtime tentang perubahan. Antarmuka ini mewarisi dari State<T>, di mana value hanya dapat dibaca. Arsitektur dua tingkat ini memungkinkan pemisahan akses: komponen yang hanya perlu membaca nilai mendapatkan State<T>, dan komponen pemilik — MutableState<T>.

Implementasi default MutableState adalah kelas internal SnapshotMutableStateImpl, yang menggunakan mekanisme snapshot untuk melacak perubahan. Ketika setter value dipanggil, snapshot saat ini mencatat penulisan dan menandai semua ObservedScope (area observasi) yang terdaftar sebagai tidak valid. Area-area ini (biasanya fungsi Composable) akan direkomposisi pada frame berikutnya. Seluruh proses terjadi secara sinkron dan tanpa penguncian berkat arsitektur Lock-free snapshot.

State vs MutableState: State — adalah antarmuka hanya-baca, digunakan untuk API publik komponen. Ketika Anda mendeklarasikan parameter fungsi Composable sebagai State<Int>, Anda menjamin bahwa komponen dapat membaca tetapi tidak dapat mengubah status. MutableState digunakan di dalam komponen pemilik. Pemisahan semacam ini — salah satu praktik dasar Compose — mencegah perubahan yang tidak sah.

Hierarki State, MutableState dan antarmuka turunan

Hierarki antarmuka status di Compose memiliki beberapa tingkat. Di puncak — State<T> dengan value hanya-baca. Di bawah — MutableState<T> dengan value baca-tulis. Selanjutnya adalah versi primitif khusus: MutableIntState, MutableFloatState, MutableLongState, MutableBooleanState dan lainnya, yang menghindari auto-boxing primitif.

MutableDoubleState dan MutableLongState — tipe yang kurang umum tetapi tetap ada. Antarmuka koleksi: MutableListState — untuk melacak perubahan di dalam daftar, MutableStateMap — untuk peta. Masing-masing antarmuka ini dioptimalkan untuk skenario tertentu dan memperluas MutableState dasar dengan metode tambahan untuk bekerja dengan koleksi.

SnapshotStateList dan SnapshotStateMap — adalah implementasi dari daftar dan peta yang dapat diubah, kompatibel dengan snapshot. Mereka memungkinkan pelacakan tidak hanya penggantian nilai, tetapi juga perubahan internal: penambahan elemen ke daftar, penghapusan, modifikasi elemen yang ada. Untuk struktur seperti itu, mutableStateListOf() dan mutableStateMapOf() membuat koleksi yang dapat diamati sesuai.

AntarmukaTujuanMetode pembuatan
State<T>Wadah hanya-baca
MutableState<T>Wadah baca-tulismutableStateOf()
MutableIntStateInt primitif tanpa boxingmutableIntStateOf()
MutableFloatStateFloat primitif tanpa boxingmutableFloatStateOf()
SnapshotStateListDaftar yang dapat diamatimutableStateListOf()
SnapshotStateMapPeta yang dapat diamatimutableStateMapOf()

SnapshotMutationPolicy: kapan memicu rekomposisi

SnapshotMutationPolicy — adalah antarmuka yang menentukan kapan perubahan MutableState dianggap signifikan. mutableStateOf menerima policy sebagai argumen kedua. Implementasi standar: structuralEquality() (equals), referentialEquality() (===), neverEqualPolicy() (selalu menganggap perubahan signifikan). Untuk logika kustom, Anda dapat mengimplementasikan policy Anda sendiri.

structuralEquality() — perilaku default. Compose membandingkan nilai baru dengan yang lama melalui equals(). Jika hasilnya true — rekomposisi TIDAK dipicu. Ini nyaman untuk primitif dan data class, di mana dua instance dengan bidang yang sama dianggap sama. Masalah: jika data class berisi List, equals() melakukan perbandingan mendalam, yang bisa mahal untuk daftar besar.

referentialEquality() — membandingkan referensi melalui ===. Rekomposisi hanya dipicu saat menetapkan objek lain, bahkan jika kontennya identik. Ini optimal untuk data class yang tidak dapat diubah, di mana setiap instance baru menjamin perubahan. neverEqualPolicy() — selalu menganggap perubahan signifikan tanpa melakukan perbandingan. Berguna ketika setter jarang dipanggil dan tidak perlu membuang waktu untuk equals.

kotlin
    // Perbandingan kebijakan dalam praktik
data class User(val name: String, val age: Int)

@Composable
fun UserProfile() {
    // structuralEquality: rekomposisi HANYA jika data berubah
    var user1 by remember {
        mutableStateOf(User("Alice", 30))
    }

    // referentialEquality: rekomposisi pada SETIAP penugasan
    var user2 by remember {
        mutableStateOf(User("Bob", 25),
            SnapshotMutationPolicy.referentialEquality())
    }

    // user1: copy() dengan bidang yang sama TIDAK memicu rekomposisi
    // user2: bahkan user2.copy() == user2 memicu rekomposisi (ref baru)
}

State Primitif: MutableIntState, MutableFloatState, MutableLongState

MutableIntState primitif dan sejenisnya — adalah antarmuka khusus yang menyimpan primitif tanpa auto-boxing. MutableState<Int> biasa menyimpan Int sebagai Integer, yang pada setiap penulisan membuat objek di heap. MutableIntState menyimpan int (primitif), sepenuhnya menghilangkan overhead pembungkusan. Ini sangat penting pada pembaruan frekuensi tinggi — penghitung, posisi scroll, nilai animasi.

mutableIntStateOf(), mutableFloatStateOf(), mutableLongStateOf() — fungsi yang membuat MutableState primitif. Antarmuka tersebut bernama MutableIntState, MutableFloatState, MutableLongState. Mereka memperluas MutableState<Int>, MutableState<Float> dan MutableState<Long> masing-masing, menambahkan properti intValue sebagai akses cepat ke primitif. Dalam implementasi internal mereka, AtomicInteger digunakan untuk baca/tulis tanpa kunci.

Penerapan: penghitung (Int), posisi scroll (Float offset), stempel waktu (Long). Di sebagian besar skenario sehari-hari, perbedaan kinerja tidak terlihat, tetapi di LazyList dengan ribuan elemen dan animasi transisi, State primitif memberikan peningkatan yang nyata. Google merekomendasikan penggunaan State primitif untuk skenario tipikal daripada mutableStateOf universal.

kotlin
@Composable
fun ScrollCounter() {
    // Buruk: pembungkusan pada setiap pembaruan
    var badCount by remember { mutableStateOf(0) }

    // Baik: tanpa pembungkusan, penyimpanan primitif
    var goodCount by remember { mutableIntStateOf(0) }

    // Penggunaan identik
    Button(onClick = { goodCount++ }) {
        Text("Count: $goodCount")
    }
}

Contoh praktis bekerja dengan MutableState

Mari kita lihat komponen TodoList, di mana MutableState digunakan dalam dua bentuk: sebagai variabel terpisah untuk status input dan sebagai SnapshotStateList untuk daftar tugas dinamis. Keduanya menggunakan delegasi untuk keringkasan kode.

kotlin
data class TodoItem(val id: Int, val text: String, val isDone: Boolean = false)

@Composable
fun TodoScreen() {
    var inputText by remember { mutableStateOf("") }
    val items = remember { mutableStateListOf() }

    Column(modifier = Modifier.padding(16.dp)) {
        Row {
            TextField(
                value = inputText,
                onValueChange = { inputText = it }
            )
            Button(onClick = {
                if (inputText.isNotBlank()) {
                    items.add(TodoItem(items.size, inputText))
                    inputText = ""
                }
            }) { Text("Tambah") }
        }

        LazyColumn {
            items(items) { item ->
                Row(modifier = Modifier.fillMaxWidth().clickable {
                    val idx = items.indexOf(item)
                    items[idx] = item.copy(isDone = !item.isDone)
                }) {
                    Checkbox(checked = item.isDone, onCheckedChange = null)
                    Text(item.text)
                }
            }
        }
    }
}

mutableStateListOf membuat SnapshotStateList — daftar yang dapat diubah yang melacak perubahan elemen individual. Saat items.add() dan items[n] = newValue dipanggil, Compose melihat mutasi dan merekomposisi hanya elemen LazyColumn yang berubah. inputText — MutableState<String> biasa. Kombinasi dua tipe MutableState (tunggal dan koleksi) — pola umum untuk layar dengan formulir dan daftar.

Pertanyaan yang Sering Diajukan

Bisakah MutableState digunakan tanpa remember?

MutableState tanpa remember akan dibuat ulang pada setiap rekomposisi. Setiap panggilan baru mutableStateOf membuat objek baru, dan nilai lama hilang. Selalu gunakan remember untuk mempertahankan State antar rekomposisi, kecuali jika State dibuat di luar Composable (misalnya di ViewModel).

Bagaimana cara mengubah MutableState menjadi variabel biasa?

Baca .value sekali di luar snapshot melalui snapshot { }. Tetapi ini menonaktifkan reaktivitas — perubahan tidak lagi memicu rekomposisi. Untuk pembacaan satu kali tanpa langganan, gunakan currentValue() di dalam snapshot tanpa membaca.

Mana yang lebih cepat: mutableStateOf atau mutableIntStateOf?

mutableIntStateOf lebih cepat karena tidak memerlukan pembungkusan int ke Integer. Pada ribuan pembaruan per detik (animasi, scroll) perbedaannya bisa mencapai 30-50% dari waktu alokasi. Pada pembaruan jarang (klik, input teks) perbedaannya tidak signifikan.

Bisakah MutableState digunakan sebagai argumen fungsi Composable?

Bisa, tetapi tidak disarankan. Alih-alih MutableState, kirimkan State (hanya-baca) + lambda onValueChange. Ini mengimplementasikan pola State Hoisting dan membuat komponen dapat digunakan kembali. Komponen yang menerima MutableState melanggar aliran data searah.

Bagaimana cara membuat implementasi MutableState kustom?

Implementasikan antarmuka MutableState dan berikan override var value dengan getter dan setter. Di setter Anda dapat menambahkan validasi atau pencatatan. Untuk kompatibilitas mundur dengan Compose Runtime, bungkus implementasi Anda dalam snapshotFlow atau gunakan snapshotIncrement.

Kesimpulan

  • MutableState — antarmuka dasar untuk status yang dapat diamati dan berubah di Compose
  • State — versi hanya-baca untuk transmisi data tanpa hak perubahan
  • SnapshotMutationPolicy mengelola kondisi pemicu rekomposisi saat perubahan
  • State Primitif (MutableIntState dll.) menghilangkan overhead auto-boxing
  • SnapshotStateList dan SnapshotStateMap melacak perubahan internal koleksi
  • Rekomposisi dipicu secara otomatis pada setiap panggilan setter value
  • Rekomendasi: gunakan MutableState untuk kepemilikan status dan State untuk transmisi ke bawah

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga