Kullanıcı arayüzü katmanı

Kullanıcı arayüzünün görevi, uygulama verilerini ekranda göstermektir. Kullanıcı arayüzü, kullanıcı etkileşiminin birincil noktası olarak da işlev görür. Veriler, kullanıcı etkileşimi (ör. düğmeye basma) veya harici giriş (ör. ağ yanıtı) nedeniyle her değiştiğinde kullanıcı arayüzü bu değişiklikleri yansıtacak şekilde güncellenir. Kullanıcı arayüzü, veri katmanından alınan uygulama durumunun görsel bir temsilidir.

Ancak veri katmanından aldığınız uygulama verileri genellikle görüntülemeniz gereken bilgilerden farklı bir biçimdedir. Örneğin, kullanıcı arayüzü için verilerin yalnızca bir kısmına ihtiyacınız olabilir veya kullanıcıyla alakalı bilgileri sunmak için iki farklı veri kaynağını birleştirmeniz gerekebilir. Uyguladığınız mantıktan bağımsız olarak, kullanıcı arayüzüne tam olarak oluşturulması için gereken tüm bilgileri iletmeniz gerekir. Kullanıcı arayüzü katmanı, uygulama verilerindeki değişiklikleri kullanıcı arayüzünün sunabileceği bir forma dönüştüren ve ardından bu formu görüntüleyen ardışık düzendir.

Tipik bir mimaride, kullanıcı arayüzü katmanının kullanıcı arayüzü öğeleri durum tutuculara, durum tutucular ise veri katmanındaki veya isteğe bağlı alan katmanındaki sınıflara bağlıdır.
Şekil 1. Uygulama mimarisinde kullanıcı arayüzü katmanının rolü.

Temel bir örnek olay

Kullanıcının okuması için haber makaleleri getiren bir uygulamayı ele alalım. Uygulamada, okunabilecek makalelerin sunulduğu bir makale ekranı vardır. Ayrıca, oturum açmış kullanıcılar, öne çıkan makaleleri yer işaretlerine ekleyebilir. Herhangi bir zamanda çok sayıda makale olabileceği için okuyucular makalelere kategoriye göre göz atabilmelidir. Özetle, uygulama kullanıcıların şunları yapmasına olanak tanır:

  • Okunabilecek makaleleri görüntüleyin.
  • Makalelere kategoriye göre göz atın.
  • Oturum açıp belirli makalelere yer işareti koyma
  • Uygun olduğunuz takdirde bazı premium özelliklere erişebilirsiniz.
Makale önizlemelerini gösteren örnek bir haber uygulaması. Önizlemelerden biri yer işaretlerine eklenmiş.
Şekil 2. Kullanıcı arayüzü örnek olay incelemesi için örnek bir haber uygulaması.

Aşağıdaki bölümlerde, tek yönlü veri akışının ilkelerini tanıtmak için bu örnek bir vaka çalışması olarak kullanılmaktadır. Ayrıca, bu ilkelerin kullanıcı arayüzü katmanına yönelik uygulama mimarisi bağlamında çözmeye yardımcı olduğu sorunlar da gösterilmektedir.

Kullanıcı arayüzü katmanı mimarisi

Kullanıcı arayüzü terimi, verileri görüntüleyen kapsayıcılar ve composable işlevler gibi kullanıcı arayüzü öğelerini ifade eder. Android kullanıcı arayüzleri oluşturmak için Jetpack Compose araç setini kullanmanızı öneririz. Veri katmanının rolü, uygulama verilerini tutmak, yönetmek ve bu verilere erişim sağlamak olduğundan kullanıcı arayüzü katmanı aşağıdaki adımları uygulamalıdır:

  1. Uygulama verilerini kullanır ve kullanıcı arayüzünün kolayca oluşturabileceği verilere dönüştürür.
  2. Kullanıcı arayüzünde oluşturulabilen verileri kullanır ve bunları kullanıcıya sunmak için kullanıcı arayüzü öğelerine dönüştürür.
  3. Birleştirilmiş kullanıcı arayüzü öğelerinden gelen kullanıcı girişi etkinliklerini kullanın ve etkilerini gerektiği gibi kullanıcı arayüzü verilerine yansıtın.
  4. 1-3 arasındaki adımları gerektiği kadar tekrarlayın.

Bu kılavuzun geri kalanında, bu adımları gerçekleştiren bir kullanıcı arayüzü katmanının nasıl uygulanacağı gösterilmektedir. Bu rehberde özellikle aşağıdaki görevler ve kavramlar ele alınmaktadır:

  • Kullanıcı arayüzü durumu nasıl tanımlanır?
  • Kullanıcı arayüzü durumunu oluşturma ve yönetme yöntemi olarak tek yönlü veri akışı (UDF)
  • UDF ilkelerine göre gözlemlenebilir veri türleriyle kullanıcı arayüzü durumunu kullanıma sunma
  • Gözlemlenebilir kullanıcı arayüzü durumunu kullanan bir kullanıcı arayüzü uygulama

Bunların en temeli, kullanıcı arayüzü durumunun tanımıdır.

Kullanıcı arayüzü durumunu tanımlama

Daha önce açıklanan örnek olayda kullanıcı arayüzünde, her makaleyle ilgili bazı meta verilerle birlikte makale listesi gösteriliyor. Uygulamanın kullanıcıya sunduğu bu bilgi, kullanıcı arayüzü durumudur.

Başka bir deyişle, kullanıcı arayüzü kullanıcının gördüğü şeyse kullanıcı arayüzü durumu, uygulamanın kullanıcının görmesi gerektiğini söylediği şeydir. Bir madalyonun iki yüzü gibi, kullanıcı arayüzü de kullanıcı arayüzü durumunun görsel temsilidir. Kullanıcı arayüzü durumunda yapılan değişiklikler anında kullanıcı arayüzüne yansıtılır.

Kullanıcı arayüzü, ekrandaki kullanıcı arayüzü öğelerinin kullanıcı arayüzü durumuyla bağlanması sonucunda ortaya çıkar.
Şekil 3. Kullanıcı arayüzü, ekrandaki kullanıcı arayüzü öğelerinin kullanıcı arayüzü durumuyla bağlanması sonucunda ortaya çıkar.

Örnek olay incelemesi: Haber uygulamasının şartlarını karşılamak için kullanıcı arayüzünü tam olarak oluşturmak üzere gereken bilgiler, aşağıdaki gibi tanımlanan bir NewsUiState veri sınıfında kapsüllenebilir:

data class NewsUiState(
    val isSignedIn: Boolean = false,
    val isPremium: Boolean = false,
    val newsItems: List<NewsItemUiState> = listOf(),
    val userMessages: List<Message> = listOf()
)

data class NewsItemUiState(
    val title: String,
    val body: String,
    val bookmarked: Boolean = false,
    // ...
)

Kullanıcı arayüzü durumu hakkında daha fazla bilgi için State ve Jetpack Compose başlıklı makaleyi inceleyin.

Değişmezlik

Önceki örnekteki kullanıcı arayüzü durumu tanımı sabittir. Bunun temel avantajı, değişmez nesnelerin uygulamanın belirli bir andaki durumuyla ilgili garantiler sunmasıdır. Bu sayede kullanıcı arayüzü, asıl rolüne (durumu okuma ve kullanıcı arayüzü öğelerini buna göre güncelleme) odaklanabilir. Kullanıcı arayüzü, verilerinin tek kaynağı olmadığı sürece kullanıcı arayüzü durumunu doğrudan kullanıcı arayüzünde değiştirmeyin. Bu ilkenin ihlal edilmesi, aynı bilgi için birden fazla doğru kaynağın olmasına neden olur. Bu da veri tutarsızlıklarına ve küçük hatalara yol açar.

Örneğin, önceki örnek olay çalışmasını ele alalım. Kullanıcı arayüzü durumundaki bir NewsItemUiState nesnesinde bulunan bookmarked işareti, Activity sınıfında güncellenirse bu işaret, bir makalenin yer işaretli durumunun kaynağı olarak veri katmanıyla yarışır. Değişmez veri sınıfları, bu tür tutarsızlıkları önlemek için çok yararlıdır.

Bu kılavuzdaki adlandırma kuralları

Bu kılavuzda, kullanıcı arayüzü durumu sınıfları, ekranın veya ekranın bir bölümünün işlevine göre adlandırılır. Kural şöyledir:

functionality + UiState.

Örneğin, haber gösteren bir ekranın durumu NewsUiState, haber öğeleri listesindeki bir haber öğesinin durumu ise NewsItemUiState olarak adlandırılabilir.

Tek yönlü veri akışıyla durumu yönetme

Önceki bölümde, kullanıcı arayüzü durumunun, kullanıcı arayüzünün oluşturulması için gereken ayrıntıların değişmez bir anlık görüntüsü olduğu belirtilmişti. Ancak uygulamalardaki verilerin dinamik yapısı, durumun zaman içinde değişebileceği anlamına gelir. Bu durum, kullanıcı etkileşiminden veya uygulamayı doldurmak için kullanılan temel verileri değiştiren diğer etkinliklerden kaynaklanabilir.

Bu etkileşimler, işlenmeleri için bir aracıdan yararlanabilir. Bu aracı, her etkinliğe uygulanacak mantığı tanımlar ve kullanıcı arayüzü durumu oluşturmak için destekleyen veri kaynaklarını dönüştürür. Bu etkileşimler ve mantıkları kullanıcı arayüzünde yer alsa da kullanıcı arayüzü çok fazla sorumluluk üstlendiği için bu durum hızla kontrolden çıkabilir. Ayrıca, bu durum test edilebilirliği de etkileyebilir. Bunun nedeni, ortaya çıkan kodun sıkı bir şekilde bağlı olmasıdır. Kullanıcı arayüzü durumu çok basit olmadığı sürece, kullanıcı arayüzünün tek sorumluluğunun kullanıcı arayüzü durumunu kullanmak ve görüntülemek olduğundan emin olun.

Bu bölümde, bu sağlıklı sorumluluk ayrımını zorunlu kılmaya yardımcı olan bir mimari kalıp olan Tek Yönlü Veri Akışı (UDF) ele alınmaktadır.

Durum bilgisi depolayıcılar

Durum sahipleri, kullanıcı arayüzü durumu oluşturmaktan ve bu durumu oluşturmak için gereken mantıktan sorumlu sınıflardır. Durum tutucular, yönettikleri ilgili kullanıcı arayüzü öğelerinin kapsamına bağlı olarak çeşitli boyutlarda olabilir. Örneğin, alt uygulama çubuğu gibi tek bir widget'tan tam bir ekrana veya gezinme hedefine kadar değişebilir.

İkinci durumda, tipik uygulama bir ViewModel örneğidir. Ancak uygulamanın gereksinimlerine bağlı olarak basit bir sınıf yeterli olabilir. Örneğin, örnek olaydaki Haberler uygulaması, o bölümde gösterilen ekranın kullanıcı arayüzü durumunu oluşturmak için durum tutucu olarak NewsViewModel sınıfını kullanır.

Kullanıcı arayüzü ile durum üreticisi arasındaki bağımlılığı modellemenin birçok yolu vardır. Ancak kullanıcı arayüzü ile ViewModel sınıfı arasındaki etkileşim büyük ölçüde etkinlik girişi ve bunun sonucunda ortaya çıkan durum çıkışı olarak anlaşılabilir. Bu nedenle, ilişki aşağıdaki şemada gösterildiği gibi temsil edilebilir:

Uygulama verileri, veri katmanından ViewModel'e akar. Kullanıcı arayüzü durumu, ViewModel'den kullanıcı arayüzü öğelerine, etkinlikler ise kullanıcı arayüzü öğelerinden ViewModel'e akar.
Şekil 4. UDF'nin uygulama mimarisinde nasıl çalıştığını gösteren şema.

Durumun aşağı, etkinliklerin ise yukarı doğru aktığı bu düzene tek yönlü veri akışı (UDF) adı verilir. Bu kalıbın uygulama mimarisi üzerindeki etkileri şunlardır:

  • ViewModel, kullanıcı arayüzü tarafından kullanılacak durumu tutar ve kullanıma sunar. Kullanıcı arayüzü durumu, ViewModel tarafından dönüştürülen uygulama verileridir.
  • Kullanıcı arayüzü, kullanıcı etkinlikleri hakkında ViewModel'i bilgilendirir.
  • ViewModel, kullanıcı işlemlerini işler ve durumu günceller.
  • Güncellenen durum, oluşturulmak üzere kullanıcı arayüzüne geri gönderilir.
  • Yukarıdaki işlem, durum mutasyonuna neden olan tüm etkinlikler için tekrarlanır.

ViewModel, gezinme hedefleri veya ekranlar için verileri almak ve bunları kullanıcı arayüzü durumuna dönüştürmek üzere depolarla veya kullanım alanı sınıflarıyla birlikte çalışır. Ayrıca, durumun mutasyonlarına neden olabilecek etkinliklerin etkilerini de dahil eder. Daha önce bahsedilen örnek olay, her biri başlık, açıklama, kaynak, yazar adı, yayınlanma tarihi ve yer işaretlerine eklenip eklenmediği bilgilerini içeren bir makale listesi içerir. Her makale öğesinin kullanıcı arayüzü aşağıdaki gibi görünür:

Kullanıcı arayüzünde küçük resim, makale başlığı, yazar, makalenin tahmini okuma süresi ve yer işareti simgesi gösteriliyor.
Şekil 5. Örnek olay uygulamasındaki bir makale öğesinin kullanıcı arayüzü.

Bir kullanıcının makale işaretleme isteği, durum mutasyonlarına neden olabilecek bir etkinlik örneğidir. Durum üreticisi olarak ViewModel, kullanıcı arayüzü durumundaki tüm alanları doldurmak için gereken tüm mantığı tanımlamak ve kullanıcı arayüzünün tam olarak oluşturulması için gereken etkinlikleri işlemekle sorumludur.

Kullanıcı bir makaleye yer işareti koyduğunda kullanıcı arayüzü etkinliği gerçekleşir. ViewModel, durum değişikliği hakkında veri katmanını bilgilendirir. Veri katmanı, veri değişikliğini kalıcı hale getirir ve uygulama verilerini günceller. Yer işaretli makaleyi içeren yeni uygulama verileri, ViewModel'e aktarılır. ViewModel daha sonra yeni kullanıcı arayüzü durumunu oluşturur ve görüntülenmesi için kullanıcı arayüzü öğelerine aktarır.
Şekil 6. UDF'deki etkinlik ve veri döngüsünü gösteren diyagram.

Aşağıdaki bölümlerde, durum değişikliklerine neden olan etkinlikler ve bu etkinliklerin kullanıcı tanımlı işlevler (UDF) kullanılarak nasıl işlenebileceği daha ayrıntılı olarak ele alınmaktadır.

Mantık türleri

Bir makaleyi yer işaretlerine eklemek, uygulamanıza değer kattığı için iş mantığına örnek verilebilir. Bu konuda daha fazla bilgi edinmek için veri katmanı sayfasına bakın. Ancak, tanımlanması gereken farklı mantık türleri vardır:

  • İş mantığı, uygulama verileriyle ilgili ürün koşullarının uygulanmasıdır. Daha önce de belirtildiği gibi, bir örnek olarak, vaka çalışması uygulamasında bir makaleyi yer işaretlerine ekleme verilebilir. İş mantığı genellikle alan veya veri katmanlarına yerleştirilir ancak kullanıcı arayüzü katmanına asla yerleştirilmez.
  • Kullanıcı arayüzü davranış mantığı veya kullanıcı arayüzü mantığı, durum değişikliklerinin ekranda nasıl gösterileceğidir. Örneğin, Android Resources kullanarak ekranda gösterilecek doğru metni elde etme, kullanıcı bir düğmeyi tıkladığında belirli bir ekrana gitme veya toast ya da snackbar kullanarak ekranda kullanıcı mesajı gösterme.

Kullanıcı arayüzü mantığını kullanıcı arayüzünde tutun, ViewModel'de tutmayın. Özellikle Context gibi kullanıcı arayüzü türleri söz konusu olduğunda bu kurala uyun. Kullanıcı arayüzünün karmaşıklığı artarsa ve test edilebilirliği ve sorumlulukların ayrılmasını sağlamak için kullanıcı arayüzü mantığını başka bir sınıfa devretmek isterseniz durum tutucu olarak basit bir sınıf oluşturabilirsiniz. Kullanıcı arayüzünde oluşturulan basit sınıflar, kullanıcı arayüzünün yaşam döngüsünü takip ettikleri için Android SDK bağımlılıklarını alabilir. ViewModel nesnelerinin ömrü daha uzundur.

Durum tutucular ve bunların kullanıcı arayüzü oluşturmaya yardımcı olma bağlamına nasıl uyduğu hakkında daha fazla bilgi için Jetpack Compose State rehberine bakın.

Neden kullanıcı tanımlı işlev kullanmalısınız?

UDF, Şekil 4'te gösterildiği gibi durum üretiminin döngüsünü modeller. Ayrıca, durum değişikliklerinin başladığı yer, dönüştürüldüğü yer ve nihayetinde kullanıldığı yer birbirinden ayrılır. Bu ayrım, kullanıcı arayüzünün adının tam olarak ima ettiği şeyi yapmasını sağlar: durum değişikliklerini gözlemleyerek bilgileri görüntüler ve bu değişiklikleri ViewModel'e ileterek kullanıcı niyetini aktarır.

Başka bir deyişle, kullanıcı tanımlı işlevler aşağıdakilere olanak tanır:

  • Veri tutarlılığı. Kullanıcı arayüzü için tek bir doğruluk kaynağı vardır.
  • Test edilebilirlik. Durum kaynağı yalıtılmış olduğundan kullanıcı arayüzünden bağımsız olarak test edilebilir.
  • Bakım yapılabilirlik. Durumun değişimi, iyi tanımlanmış bir kalıba uyar. Bu kalıpta değişimler hem kullanıcı etkinliklerinin hem de verileri çektiği kaynakların sonucudur.

Kullanıcı arayüzü durumunu kullanıma sunma

Kullanıcı arayüzü durumunuzu tanımlayıp bu durumun üretimini nasıl yöneteceğinizi belirledikten sonraki adım, üretilen durumu kullanıcı arayüzünde göstermektir.

Durum üretimini yönetmek için UDF kullanırken üretilen durumu bir akış olarak düşünebilirsiniz. Diğer bir deyişle, zaman içinde durumun birden fazla sürümü üretilir. Kullanıcı arayüzü durumunu StateFlow gibi gözlemlenebilir bir veri tutucuda kullanıma sunun. Bu sayede, kullanıcı arayüzü, ViewModel'den verileri doğrudan manuel olarak çekmek zorunda kalmadan durumdaki değişikliklere tepki verebilir. Bu, kullanıcı arayüzü durumunun her zaman en son sürümünün önbelleğe alınması avantajını da sağlar. Bu, yapılandırma değişikliklerinden sonra durumun hızlı bir şekilde geri yüklenmesi için yararlıdır.

class NewsViewModel(
    // ...
) : ViewModel() {

    val uiState: NewsUiState = /* ... */
}

Kotlin akışlarına giriş için Android'de Kotlin akışları başlıklı makaleyi inceleyin. StateFlow öğesini gözlemlenebilir veriler tutucu olarak kullanmayı öğrenmek için Jetpack Compose'da Gelişmiş Durum ve Yan Etkiler adlı codelab'e bakın.

Kullanıcı arayüzüne sunulan verilerin nispeten basit olduğu durumlarda, durum sahibi yayını ile ilişkili ekranı veya kullanıcı arayüzü öğesi arasındaki ilişkiyi aktardığı için verileri bir kullanıcı arayüzü durumu türüne sarmak genellikle faydalıdır. Kullanıcı arayüzü öğesi daha karmaşık hale geldikçe kullanıcı arayüzü durumunun tanımına ekleme yapmak kolaylaşır. Böylece, kullanıcı arayüzü öğesini oluşturmak için gereken ek bilgileri ekleyebilirsiniz.

UiState akışı oluşturmanın yaygın bir yolu, mutableStateOf özelliği private set ile kullanıma sunmaktır. Bu durumda, ViewModel'deki durum değiştirilebilir ancak kullanıcı arayüzü için salt okunur kalır.

class NewsViewModel(
    // ...
) : ViewModel() {

    var uiState by mutableStateOf(NewsUiState())
        private set

    // ...
}

ViewModel daha sonra durumu dahili olarak değiştiren yöntemleri kullanıma sunabilir ve kullanıcı arayüzünün kullanması için güncellemeler yayınlayabilir. Örneğin, eşzamansız bir işlem yapmanız gereken durumu ele alalım. viewModelScope kullanarak bir coroutine başlatabilir ve tamamlandığında değiştirilebilir durumu güncelleyebilirsiniz.

class NewsViewModel(
    private val repository: NewsRepository,
    // ...
) : ViewModel() {

    var uiState by mutableStateOf(NewsUiState())
        private set

    private var fetchJob: Job? = null

    fun fetchArticles(category: String) {
        fetchJob?.cancel()
        fetchJob = viewModelScope.launch {
            try {
                val newsItems = repository.newsItemsForCategory(category)
                uiState = uiState.copy(newsItems = newsItems)
            } catch (ioe: IOException) {
                // Handle the error and notify the UI when appropriate.
                val messages = getMessagesFromThrowable(ioe)
                uiState = uiState.copy(userMessages = messages)
            }
        }
    }
}

Önceki örnekte, NewsViewModel sınıfı belirli bir kategori için makaleleri getirmeye çalışır ve ardından denemenin sonucunu (başarı veya başarısızlık) kullanıcı arayüzü durumunda yansıtır. Kullanıcı arayüzü bu duruma uygun şekilde tepki verebilir. Hata işleme hakkında daha fazla bilgi için Hataları ekranda gösterme bölümüne bakın.

Göz önünde bulundurulacak diğer noktalar

Önceki yönergelere ek olarak, kullanıcı arayüzü durumunu kullanıma sunarken aşağıdakileri göz önünde bulundurun:

  • Birbiriyle ilişkili durumları işlemek için tek bir kullanıcı arayüzü durumu nesnesi kullanın. Bu durum, tutarsızlıkların azalmasına ve kodun daha kolay anlaşılmasına yol açar. Haber öğeleri listesini ve yer işareti sayısını iki farklı akışta gösterirseniz birinin güncellendiği, diğerinin güncellenmediği bir durumla karşılaşabilirsiniz. Tek bir yayın kullandığınızda her iki öğe de güncel tutulur. Ayrıca, bazı işletme mantıkları kaynakların bir kombinasyonunu gerektirebilir. Örneğin, yer işareti düğmesini yalnızca kullanıcının oturumu açık ve kullanıcının premium bir haber hizmetine abone olması durumunda göstermeniz gerekebilir. Kullanıcı arayüzü durumu sınıfını aşağıdaki gibi tanımlayabilirsiniz:

    data class NewsUiState(
        val isSignedIn: Boolean = false,
        val isPremium: Boolean = false,
        val newsItems: List<NewsItemUiState> = listOf()
    )
    
    val NewsUiState.canBookmarkNews: Boolean get() = isSignedIn && isPremium

    Bu beyanda, yer işareti düğmesinin görünürlüğü diğer iki özelliğin türetilmiş bir özelliğidir. İş mantığı karmaşıklaştıkça tüm özelliklerin anında kullanılabildiği tek bir UiState sınıfına sahip olmak giderek daha önemli hale gelir.

  • Kullanıcı arayüzü durumları: tek yayın mı yoksa birden fazla yayın mı? Kullanıcı arayüzü durumunu tek bir akışta mı yoksa birden fazla akışta mı kullanacağınızı seçerken temel kılavuz ilke, yayınlanan öğeler arasındaki ilişkidir. Tek akışlı bir yayının en büyük avantajları kolaylık ve veri tutarlılığıdır: Devlet hizmetlerinden yararlanan tüketiciler, her zaman en güncel bilgilere erişebilir. Ancak ViewModel'den ayrı durum akışlarının uygun olabileceği durumlar vardır:

    • İlgisiz veri türleri: Kullanıcı arayüzünü oluşturmak için gereken bazı durumlar birbirinden tamamen bağımsız olabilir. Bu gibi durumlarda, özellikle bu durumlardan biri diğerinden daha sık güncelleniyorsa bu farklı durumları bir araya getirmenin maliyetleri faydalarından daha ağır basabilir.

    • UiState karşılaştırma: Bir UiState nesnesinde ne kadar çok alan varsa akışın, alanlarından birinin güncellenmesi sonucunda yayınlanma olasılığı o kadar yüksek olur. Kullanıcı arayüzü öğelerinde, ardışık emisyonların farklı mı yoksa aynı mı olduğunu anlamak için bir karşılaştırma mekanizması olmadığından her emisyon, kullanıcı arayüzü öğesinin güncellenmesine neden olur. Bu nedenle, distinctUntilChanged() gibi Flow API yöntemleri kullanılarak azaltma yapılması gerekebilir.

Oluşturma ve kullanıcı arayüzü durumu hakkında daha fazla bilgi için Composable'ların yaşam döngüsü başlıklı makaleyi inceleyin.

Kullanıcı arayüzü durumunu kullanma

Kullanıcı arayüzünde UiState nesneleri akışını kullanmak için kullandığınız gözlemlenebilir veri türü için terminal operatörünü kullanın. Örneğin, Kotlin akışları için collect() yöntemini veya varyasyonlarını kullanın.

Kullanıcı arayüzünde gözlemlenebilir veri tutucuları kullanırken kullanıcı arayüzünün yaşam döngüsünü göz önünde bulundurun. Kullanıcıya composable gösterilmediğinde kullanıcı arayüzünün kullanıcı arayüzü durumunu gözlemlemesini engelleyin. Bu konu hakkında daha fazla bilgi edinmek için bu blog yayınını inceleyin. Akışları kullanırken yaşam döngüsüyle ilgili sorunları uygun coroutine kapsamı ve collectAsStateWithLifecycle API'siyle ele almak en iyisidir:

@Composable
private fun ConversationScreen(
    conversationViewModel: ConversationViewModel = viewModel()
) {

    val messages by conversationViewModel.messages.collectAsStateWithLifecycle()

    ConversationScreen(
        messages = messages,
        onSendMessage = { message: Message -> conversationViewModel.sendMessage(message) }
    )
}

@Composable
private fun ConversationScreen(
    messages: List<Message>,
    onSendMessage: (Message) -> Unit
) {

    MessagesList(messages, onSendMessage)
    /* ... */
}

Devam eden işlemleri göster

UiState sınıfında yükleme durumlarını temsil etmenin basit bir yolu, boolean alan kullanmaktır:

data class NewsUiState(
    val isFetchingArticles: Boolean = false,
    // ...
)

Bu işaretin değeri, kullanıcı arayüzünde ilerleme çubuğunun olup olmadığını gösterir.

@Composable
fun LatestNewsScreen(
    modifier: Modifier = Modifier,
    viewModel: NewsViewModel = viewModel()
) {
    Box(modifier.fillMaxSize()) {

        if (viewModel.uiState.isFetchingArticles) {
            CircularProgressIndicator(Modifier.align(Alignment.Center))
        }

        // Add other UI elements. For example, the list.
    }
}

Hataları ekranda göster

Her ikisi de varlıklarını veya yokluklarını belirten boole değerleriyle kolayca temsil edildiğinden, kullanıcı arayüzünde hataları göstermek devam eden işlemleri göstermeye benzer. Ancak hatalar, kullanıcıya geri iletilecek ilişkili bir mesaj veya başarısız işlemi yeniden deneyen ilişkili bir işlem de içerebilir. Bu nedenle, devam eden bir işlem yüklenirken veya yüklenmezken hata durumlarının, hatanın bağlamına uygun meta verileri barındıran veri sınıflarıyla modellenmesi gerekebilir.

Makaleler getirilirken ilerleme çubuğunu gösteren önceki örneği ele alalım. Bu işlem hatayla sonuçlanırsa kullanıcıya neyin yanlış gittiğini ayrıntılı olarak açıklayan bir veya daha fazla mesaj göstermek isteyebilirsiniz.

data class Message(val id: Long, val message: String)

data class NewsUiState(
    val userMessages: List<Message> = listOf(),
    // ...
)

Ardından, hata mesajlarını kullanıcıya snackbar gibi kullanıcı arayüzü öğeleri şeklinde gösterebilirsiniz. Kullanıcı arayüzü etkinliklerinin nasıl oluşturulduğu ve kullanıldığı hakkında daha fazla bilgi için Kullanıcı arayüzü etkinlikleri başlıklı makaleyi inceleyin.

İş parçacığı oluşturma ve eşzamanlılık

ViewModel'de gerçekleştirilen tüm işlemlerin main-safe (ana iş parçacığından çağrılması güvenli) olduğundan emin olun. Veri ve alan katmanları, işi farklı bir iş parçacığına taşımaktan sorumludur.

Bir ViewModel uzun süren işlemler gerçekleştiriyorsa bu mantığı arka plan iş parçacığına taşımaktan da sorumludur. Kotlin eş yordamları, eşzamanlı işlemleri yönetmek için harika bir yöntemdir ve Jetpack Architecture Components, bu eş yordamlar için yerleşik destek sunar. Android uygulamalarında eş yordamları kullanma hakkında daha fazla bilgi edinmek için Android'de Kotlin eş yordamları başlıklı makaleyi inceleyin.

Uygulama gezinmesindeki değişiklikler genellikle etkinlik benzeri yayınlardan kaynaklanır. Örneğin, SignInViewModel sınıfı oturum açtıktan sonra UiState, isSignedIn alanı true olarak ayarlanmış olabilir. Bu tür tetikleyicileri, önceki Consume UI state (Kullanıcı arayüzü durumunu tüketme) bölümünde ele alınanlarla aynı şekilde kullanın ancak tüketim uygulamasını Navigation component'e (Gezinme bileşeni) erteleyin.

Kullanıcı arayüzünde gezinme hakkında daha fazla bilgi için Gezinme 3 başlıklı makaleyi inceleyin.

Sayfalandırma

Paging kitaplığı, kullanıcı arayüzünde PagingData adlı bir türle kullanılır. PagingData, zaman içinde değişebilecek öğeleri temsil ettiğinden ve içerdiğinden (diğer bir deyişle, değişmez bir tür olmadığından) bunu değişmez bir kullanıcı arayüzü durumunda temsil etmeyin. Bunun yerine, ViewModel'den kendi akışında bağımsız olarak kullanıma sunun.

Aşağıdaki örnekte Paging kitaplığının Compose API'si gösterilmektedir:

@Composable
fun MyScreen(flow: Flow<PagingData<String>>) {
    val lazyPagingItems = flow.collectAsLazyPagingItems()
    LazyColumn {
        items(
            lazyPagingItems.itemCount,
            key = lazyPagingItems.itemKey { it }
        ) { index ->
            val item = lazyPagingItems[index]
            Text("Item is $item")
        }
    }
}

Animasyonlar

Üst düzeyde sorunsuz gezinme geçişleri sağlamak için animasyonu başlatmadan önce ikinci ekranın verileri yüklemesini bekleyebilirsiniz.

Gezinme geçişleri hakkında daha fazla bilgi için Navigation 3 ve Compose'da paylaşılan öğe geçişleri başlıklı makaleleri inceleyin.

Ek kaynaklar

İçeriği görüntüleme

Örnekler

Aşağıdaki Google örneklerinde kullanıcı arayüzü katmanının kullanımı gösterilmektedir. Bu rehberin nasıl uygulandığını görmek için aşağıdaki kaynakları inceleyin: