Di Compose, UI tidak dapat diubah—tidak ada cara untuk mengupdatenya setelah
digambar. Yang dapat Anda kontrol adalah status UI Anda. Setiap kali status UI berubah, Compose membuat ulang bagian hierarki UI yang telah berubah. Composable dapat menerima
status dan menampilkan peristiwa—misalnya TextField
menerima nilai dan menampilkan
onValueChange
callback yang meminta handler callback untuk mengubah
nilai.
var name by remember { mutableStateOf("") } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } )
Karena composable menerima status dan menampilkan peristiwa, pola aliran data searah akan sesuai dengan Jetpack Compose. Panduan ini berfokus pada cara menerapkan pola aliran data searah di Compose, cara menerapkan peristiwa dan pemegang status, dan cara menggunakan ViewModel di Compose.
Aliran data searah
Aliran data searah (ADS) adalah pola desain dengan status mengalir ke bawah dan peristiwa mengalir ke atas. Dengan mengikuti aliran data searah, Anda dapat memisahkan composable yang menampilkan status di UI dari bagian aplikasi yang menyimpan dan mengubah status.
Loop update UI untuk aplikasi yang menggunakan aliran data searah terlihat seperti ini:
- Peristiwa: Bagian UI menghasilkan peristiwa dan meneruskannya ke atas, seperti klik tombol yang diteruskan ke ViewModel untuk ditangani; atau peristiwa diteruskan dari lapisan lain aplikasi Anda, seperti menunjukkan bahwa sesi pengguna telah berakhir.
- Status update: Handler peristiwa dapat mengubah status.
- Status tampilan: Pemegang status akan menurunkan status, dan UI akan menampilkannya.
![](https://developer.android.com/static/develop/ui/compose/images/state-unidirectional-flow.png?authuser=19&hl=id)
Mengikuti pola ini saat menggunakan Jetpack Compose memberikan beberapa keuntungan:
- Kemampuan untuk diuji: Memisahkan status dari UI yang menampilkannya akan mempermudah pengujian keduanya secara terpisah.
- Enkapsulasi status: Karena status hanya dapat diupdate di satu tempat dan hanya ada satu sumber ketepatan untuk status composable, kecil kemungkinan Anda membuat bug karena status yang tidak konsisten.
- Konsistensi UI: Semua update status langsung tercermin di UI dengan
menggunakan pemegang status yang dapat diamati, seperti
StateFlow
atauLiveData
.
Aliran data searah di Jetpack Compose
Composable bekerja berdasarkan status dan peristiwa. Misalnya, TextField
hanya akan diupdate jika parameter value
diupdate, dan menampilkan callback onValueChange
, yaitu peristiwa yang meminta nilai diubah ke callback baru. Compose menentukan objek State
sebagai penampung nilai, dan perubahan pada nilai status akan memicu rekomposisi. Anda dapat menyimpan status dalam remember { mutableStateOf(value) }
atau rememberSaveable { mutableStateOf(value)
, bergantung pada berapa lama Anda perlu mengingat nilainya.
Jenis nilai composable TextField
adalah String
, sehingga nilai ini dapat berasal dari mana saja—dari nilai hardcode, dari ViewModel, atau diteruskan dari composable induk. Anda tidak perlu menyimpannya dalam objek State
, tetapi Anda perlu memperbarui nilainya saat onValueChange
dipanggil.
Menentukan parameter composable
Saat menentukan parameter status composable, Anda harus memperhatikan pertanyaan berikut:
- Seberapa dapat digunakan kembali atau seberapa fleksibel komposisinya?
- Bagaimana pengaruh parameter status terhadap performa composable ini?
Untuk mendorong pemisahan dan penggunaan ulang, setiap composable harus memiliki jumlah informasi minimum. Misalnya, saat mem-build composable untuk menyimpan header artikel berita, lebih baik hanya menyampaikan informasi yang perlu ditampilkan, bukan seluruh artikel berita.
@Composable fun Header(title: String, subtitle: String) { // Recomposes when title or subtitle have changed. } @Composable fun Header(news: News) { // Recomposes when a new instance of News is passed in. }
Terkadang, menggunakan parameter individual juga meningkatkan performa—misalnya, jika News
berisi lebih banyak informasi selain title
dan subtitle
, setiap kali instance baru News
diteruskan ke Header(news)
, composable akan mengomposisi ulang, meskipun title
dan subtitle
tidak berubah.
Pertimbangkan baik-baik jumlah parameter yang Anda berikan. Fungsi yang memiliki terlalu banyak parameter akan menurunkan ergonomi fungsi tersebut, sehingga dalam hal ini, mengelompokkannya dalam class lebih diutamakan.
Peristiwa di Compose
Setiap input ke aplikasi Anda harus direpresentasikan sebagai peristiwa: ketukan, perubahan teks,
dan bahkan timer atau pembaruan lainnya. Karena peristiwa ini mengubah status UI Anda,
ViewModel
harus menjadi orang yang menanganinya dan mengupdate status UI.
Lapisan UI tidak boleh mengubah status di luar pengendali peristiwa karena hal ini dapat menimbulkan ketidakkonsistenan dan bug dalam aplikasi Anda.
Memilih meneruskan nilai yang tidak dapat diubah untuk lambda status dan pengendali peristiwa. Pendekatan ini memiliki manfaat sebagai berikut:
- Anda meningkatkan penggunaan kembali.
- Anda memastikan UI tidak mengubah nilai status secara langsung.
- Anda menghindari masalah serentak karena memastikan bahwa status tidak dimutasi dari rangkaian pesan lain.
- Sering kali, Anda mengurangi kompleksitas kode.
Misalnya, composable yang menerima String
dan lambda sebagai parameter dapat dipanggil dari berbagai konteks dan sangat dapat digunakan kembali. Misalnya panel aplikasi atas di aplikasi Anda selalu menampilkan teks dan memiliki tombol kembali. Anda dapat menentukan
fungsi MyAppTopAppBar
yang dapat dikomposisi dan lebih umum yang menerima teks dan handle tombol
kembali sebagai parameter:
@Composable fun MyAppTopAppBar(topAppBarText: String, onBackPressed: () -> Unit) { TopAppBar( title = { Text( text = topAppBarText, textAlign = TextAlign.Center, modifier = Modifier .fillMaxSize() .wrapContentSize(Alignment.Center) ) }, navigationIcon = { IconButton(onClick = onBackPressed) { Icon( Icons.Filled.ArrowBack, contentDescription = localizedString ) } }, // ... ) }
ViewModels, status, dan peristiwa: contoh
Dengan menggunakan ViewModel
dan mutableStateOf
, Anda juga dapat memperkenalkan aliran data
yang searah dalam aplikasi jika salah satu hal berikut terjadi:
- Status UI Anda terekspos melalui pemegang status yang dapat diamati, seperti
StateFlow
atauLiveData
. ViewModel
menangani peristiwa yang berasal dari UI atau lapisan lain aplikasi Anda dan mengupdate holder status berdasarkan peristiwa tersebut.
Misalnya, saat menerapkan layar masuk, mengetuk tombol Login akan menyebabkan aplikasi menampilkan indikator lingkaran berputar progres dan panggilan jaringan. Jika proses login berhasil, aplikasi Anda membuka layar yang berbeda; jika terjadi error, aplikasi menampilkan Snackbar. Berikut cara membuat model status layar dan peristiwa:
Layar memiliki empat status:
- Logout: saat pengguna belum login.
- Dalam proses: saat aplikasi Anda sedang mencoba membuat pengguna login dengan melakukan panggilan jaringan.
- Error: saat terjadi error saat login.
- Login: saat pengguna login.
Anda dapat membuat model status ini sebagai class tertutup. ViewModel
mengekspos status sebagai
State
, menetapkan status awal, dan memperbarui status sesuai kebutuhan. Tujuan
ViewModel
juga menangani peristiwa login dengan mengekspos metode onSignIn()
.
class MyViewModel : ViewModel() { private val _uiState = mutableStateOf<UiState>(UiState.SignedOut) val uiState: State<UiState> get() = _uiState // ... }
Selain mutableStateOf
API, Compose menyediakan
ekstensi untuk LiveData
, Flow
, dan
Observable
untuk mendaftar sebagai pemroses dan mewakili nilai sebagai status.
class MyViewModel : ViewModel() { private val _uiState = MutableLiveData<UiState>(UiState.SignedOut) val uiState: LiveData<UiState> get() = _uiState // ... } @Composable fun MyComposable(viewModel: MyViewModel) { val uiState = viewModel.uiState.observeAsState() // ... }
Mempelajari lebih lanjut
Untuk mempelajari arsitektur di Jetpack Compose lebih lanjut, lihat referensi berikut:
Contoh
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Status dan Jetpack Compose
- Menyimpan status UI di Compose
- Menangani input pengguna