Compose'da kullanıcı arayüzü sabittir. Çizildikten sonra güncellenemez. Kontrol edebileceğiniz şey, kullanıcı arayüzünüzün durumudur. Kullanıcı arayüzünün durumu her değiştiğinde Compose, kullanıcı arayüzü ağacının değişen kısımlarını yeniden oluşturur. Birleştirilebilir öğeler, durumu kabul edebilir ve etkinlikleri gösterebilir. Örneğin, bir TextField, değeri kabul eder ve geri çağırma işleyicisinin değeri değiştirmesini isteyen bir geri çağırma onValueChange gösterir.
var name by remember { mutableStateOf("") } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } )
Birleştirilebilir öğeler durumu kabul edip etkinlikleri gösterdiğinden tek yönlü veri akışı kalıbı Jetpack Compose ile uyumludur. Bu kılavuzda, Compose'da tek yönlü veri akışı modelinin nasıl uygulanacağı, etkinliklerin ve durum bilgisi depolayıcıların nasıl uygulanacağı ve Compose'da ViewModel'lerle nasıl çalışılacağı açıklanmaktadır.
Tek yönlü veri akışı
Tek yönlü veri akışı (UDF), durumun aşağı, etkinliklerin ise yukarı doğru aktığı bir tasarım kalıbıdır. Tek yönlü veri akışını izleyerek kullanıcı arayüzünde durumu gösteren composable'ları, uygulamanızın durumu depolayan ve değiştiren bölümlerinden ayırabilirsiniz.
Tek yönlü veri akışı kullanan bir uygulamanın kullanıcı arayüzü güncelleme döngüsü şu şekildedir:
- Etkinlik: Kullanıcı arayüzünün bir kısmı etkinlik oluşturur ve bunu yukarı iletir. Örneğin, işlenmek üzere ViewModel'e iletilen bir düğme tıklaması veya uygulamanızın diğer katmanlarından iletilen bir etkinlik (ör. kullanıcı oturumunun süresinin dolduğunu belirten bir etkinlik).
- Durumu güncelleme: Bir etkinlik işleyici, durumu değiştirebilir.
- Durumu görüntüleme: Durum bilgisi depolayıcı, durumu iletir ve kullanıcı arayüzü bu durumu görüntüler.
Jetpack Compose'u kullanırken bu kalıbı takip etmek çeşitli avantajlar sağlar:
- Test edilebilirlik: Durumu, onu gösteren kullanıcı arayüzünden ayırmak, her ikisini de ayrı ayrı test etmeyi kolaylaştırır.
- Durum kapsülleme: Durum yalnızca tek bir yerde güncellenebildiğinden ve bir composable'ın durumu için tek bir doğru kaynak olduğundan, tutarsız durumlardan kaynaklanan hatalar oluşturma olasılığınız daha düşüktür.
- Kullanıcı arayüzü tutarlılığı: Tüm durum güncellemeleri,
StateFlowveyaLiveDatagibi gözlemlenebilir durum bilgisi depolayıcılar kullanılarak kullanıcı arayüzüne hemen yansıtılır.
Jetpack Compose'da tek yönlü veri akışı
Birleştirilebilir öğeler, duruma ve etkinliklere göre çalışır. Örneğin, bir TextField yalnızca value parametresi güncellendiğinde güncellenir ve bir onValueChange geri çağırma işlevi (değerin yeni bir değerle değiştirilmesini isteyen bir etkinlik) gösterir. Compose, State nesnesini bir değer tutucu olarak tanımlar ve durum değerinde yapılan değişiklikler yeniden oluşturmayı tetikler. Değeri ne kadar süre hatırlamanız gerektiğine bağlı olarak durumu bir remember { mutableStateOf(value) } veya rememberSaveable { mutableStateOf(value) } içinde tutabilirsiniz.
TextField composable'ının değer türü String olduğundan bu değer, sabit kodlanmış bir değerden, ViewModel'den veya üst composable'dan aktarılabilir. Bunu bir State nesnesinde tutmanız gerekmez ancak onValueChange çağrıldığında değeri güncellemeniz gerekir.
mutableStateOf(value), Compose'da gözlemlenebilir bir tür olanMutableStateoluşturur. Değerinde yapılan değişiklikler, bu değeri okuyan tüm composable işlevlerin yeniden oluşturulmasını planlar.remember, nesneleri oluşturmada saklar veremember'i çağıran composable, oluşturmadan kaldırıldığında nesneyi unutur.rememberSaveable, yapılandırma değişiklikleri sırasında durumuBundleiçine kaydederek korur.
Birleştirilebilir parametreleri tanımlama
Bir composable'ın durum parametrelerini tanımlarken aşağıdaki soruları göz önünde bulundurun:
- Oluşturulabilir öğe ne kadar yeniden kullanılabilir veya esnek?
- Durum parametreleri bu composable'ın performansını nasıl etkiler?
Ayrıştırmayı ve yeniden kullanımı teşvik etmek için her composable mümkün olan en az miktarda bilgi içermelidir. Örneğin, bir haber makalesinin başlığını barındıracak bir composable oluştururken haber makalesinin tamamı yerine yalnızca gösterilmesi gereken bilgileri iletmeyi tercih edin:
@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. }
Bazen ayrı parametreler kullanmak performansı da artırır. Örneğin, News yalnızca title ve subtitle'den daha fazla bilgi içeriyorsa Header(news)'e yeni bir News örneği her iletildiğinde, title ve subtitle değişmemiş olsa bile composable yeniden oluşturulur.
İlettiğiniz parametre sayısını dikkatlice değerlendirin. Çok fazla parametre içeren bir işlev, işlevin ergonomisini azaltır. Bu nedenle, bu durumda parametreleri bir sınıfta gruplandırmak tercih edilir.
Compose'da etkinlikler
Uygulamanıza yapılan her giriş bir etkinlik olarak temsil edilmelidir: dokunmalar, metin değişiklikleri, hatta zamanlayıcılar veya diğer güncellemeler. Bu etkinlikler kullanıcı arayüzünüzün durumunu değiştirdiğinden ViewModel, bu etkinlikleri işlemeli ve kullanıcı arayüzü durumunu güncellemelidir.
Kullanıcı arayüzü katmanı, hiçbir zaman etkinlik işleyicinin dışında durum değiştirmemelidir. Aksi takdirde uygulamanızda tutarsızlıklar ve hatalar oluşabilir.
Durum ve etkinlik işleyici lambda'ları için sabit değerler iletmeyi tercih edin. Bu yaklaşımın aşağıdaki avantajları vardır:
- Yeniden kullanılabilirliği artırırsınız.
- Kullanıcı arayüzünüzün, durumun değerini doğrudan değiştirmediğini doğrulayın.
- Durumun başka bir iş parçacığından değiştirilmediğinden emin olduğunuz için eşzamanlılık sorunlarından kaçınmış olursunuz.
- Genellikle kod karmaşıklığını azaltırsınız.
Örneğin, parametre olarak bir String ve lambda kabul eden bir composable, birçok bağlamdan çağrılabilir ve yüksek düzeyde yeniden kullanılabilir. Uygulamanızdaki üst uygulama çubuğunun her zaman metin gösterdiğini ve bir geri düğmesi olduğunu varsayalım. Metni ve geri düğmesi işleyicisini parametre olarak alan daha genel bir MyAppTopAppBar composable tanımlayabilirsiniz:
@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.AutoMirrored.Filled.ArrowBack, contentDescription = localizedString ) } }, // ... ) }
ViewModel'ler, durumlar ve etkinlikler: Örnek
ViewModel ve mutableStateOf kullanarak, aşağıdaki durumlardan biri geçerliyse uygulamanızda tek yönlü veri akışı da sağlayabilirsiniz:
- Kullanıcı arayüzünüzün durumu,
StateFlowveyaLiveDatagibi gözlemlenebilir durum bilgisi depolayıcılar kullanılarak gösterilir. ViewModel, kullanıcı arayüzünden veya uygulamanızın diğer katmanlarından gelen etkinlikleri işler ve durum bilgisi depolayıcıyı etkinliklere göre günceller.
Örneğin, oturum açma ekranı uygularken Oturum aç düğmesine dokunulduğunda uygulamanızda ilerleme çarkı ve ağ çağrısı gösterilmelidir. Giriş başarılı olursa uygulamanız farklı bir ekrana gider. Hata durumunda ise uygulama bir Snackbar gösterir. Ekran durumunu ve etkinliği şu şekilde modelleyebilirsiniz:
Ekranın dört durumu vardır:
- Oturum kapalı: Kullanıcı henüz oturum açmamıştır.
- Devam ediyor: Uygulamanız, ağ çağrısı yaparak kullanıcının oturumunu açmaya çalışırken.
- Hata: Oturum açma sırasında bir hata oluştuğunda.
- Oturum açıldı: Kullanıcı oturum açtığında.
Bu durumları kapalı sınıf olarak modelleyebilirsiniz. ViewModel, durumu State olarak gösterir, başlangıç durumunu ayarlar ve durumu gerektiği gibi günceller. ViewModel, bir onSignIn() yöntemi sunarak oturum açma etkinliğini de yönetir.
class MyViewModel : ViewModel() { private val _uiState = mutableStateOf<UiState>(UiState.SignedOut) val uiState: State<UiState> get() = _uiState // ... }
mutableStateOf API'sine ek olarak Compose, LiveData, Flow ve Observable için dinleyici olarak kaydolup değeri bir durum olarak temsil eden uzantılar sağlar.
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() // ... }
Daha fazla bilgi
Jetpack Compose'da mimari hakkında daha fazla bilgi edinmek için aşağıdaki kaynakları inceleyin:
Örnekler
Sizin için önerilenler
- Not: JavaScript devre dışı bırakıldığında bağlantı metni gösterilir.
- State ve Jetpack Compose
- Compose'da kullanıcı arayüzü durumunu kaydetme
- Kullanıcı girişini işleme