Kullanıcı arayüzü katmanı

Kullanıcı arayüzünün görevi, uygulama verilerini ekranda göstermektir. Kullanıcı arayüzü, kullanıcının birincil etkileşim 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. Kullanıcı arayüzü katmanının uygulama mimarisindeki 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 makaleler ekranı var. Ayrıca, oturum açmış kullanıcılar, öne çıkan makaleleri yer işaretlerine ekleyebiliyor. Herhangi bir zamanda çok sayıda makale olabileceğinden okuyucular, makalelere kategoriye göre göz atabilmelidir. Özetle, uygulama kullanıcıların aşağıdakileri yapmasına olanak tanır:

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

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

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ının aşağıdaki adımları uygulaması gerekir:

  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 tüketir 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. Gerekli olduğu sürece 1-3 arasındaki adımları 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 kılavuzda özellikle aşağıdaki görevler ve kavramlar ele alınmaktadır:

  • Kullanıcı arayüzü durumunu tanımlama
  • Kullanıcı arayüzü durumunu oluşturup yönetmek için 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 verilerin yanı sıra makalelerin 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. Aynı 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 tüm değişiklikler kullanıcı arayüzüne anında 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: 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 Durum 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ğına yol açar. Bu da veri tutarsızlıklarına ve küçük hatalara neden olur.

Ö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ştirilemez veri sınıfları, bu tür tutarsızlıkların önlenmesi 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 açıkladıkları bölümün işlevine göre adlandırılır. Kural aşağıdaki gibidir:

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ı nedeniyle durum zaman içinde değişebilir. Bu durum, kullanıcı etkileşimi veya uygulamayı doldurmak için kullanılan temel verileri değiştiren diğer etkinliklerden kaynaklanabilir.

Bu etkileşimler, işlenmek için bir aracıdan yararlanabilir. Bu aracı, her bir 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 yönetilemez hale gelebilir. 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, tek yönlü veri akışı (UDF) adı verilen ve bu sağlıklı sorumluluk ayrımını zorunlu kılmaya yardımcı olan bir mimari kalıbı 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 bilgisi depolayıcılar, yönettikleri ilgili kullanıcı arayüzü öğelerinin kapsamına bağlı olarak çeşitli boyutlarda olabilir. Bu boyutlar, alt uygulama çubuğu gibi tek bir widget'tan tam bir ekrana veya gezinme hedefine kadar değişebilir.

İkinci durumda, uygulamanın gereksinimlerine bağlı olarak basit bir sınıf yeterli olsa da genellikle ViewModel örneği kullanılır. Örneğin, örnek olaydaki Haberler uygulaması, o bölümde gösterilen ekranın kullanıcı arayüzü durumunu oluşturmak için durum bilgisi depolayıcı 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&#39;e akar. Kullanıcı arayüzü durumu, ViewModel&#39;den kullanıcı arayüzü öğelerine, etkinlikler ise kullanıcı arayüzü öğelerinden ViewModel&#39;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 değişikliğine neden olan tüm etkinlikler için tekrarlanır.

ViewModel, gezinme hedefleri veya ekranlar için veri almak ve durumu değiştirebilecek etkinliklerin etkilerini dahil ederken verileri kullanıcı arayüzü durumuna dönüştürmek üzere depolarla veya kullanım alanı sınıflarıyla birlikte çalışır. Daha önce bahsedilen örnek olay, her biri başlık, açıklama, kaynak, yazar adı, yayınlanma tarihi ve yer işareti eklenip eklenmediği bilgilerini içeren bir makale listesi içerir. Her makale öğesinin kullanıcı arayüzü şu şekilde görünür:

Vaka çalışması uygulamasından tek bir makale öğesi. 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 makaleyi yer işaretlerine eklemek isteyen kullanıcı, durum mutasyonlarına neden olabilecek bir etkinliğe örnek verilebilir. Durum üreticisi olarak ViewModel'in, kullanıcı arayüzü durumundaki tüm alanları doldurmak ve kullanıcı arayüzünün tam olarak oluşturulması için gereken etkinlikleri işlemek üzere gereken tüm mantığı tanımlaması gerekir.

Kullanıcı bir makaleye yer işareti koyduğunda kullanıcı arayüzü etkinliği gerçekleşir. ViewModel, durum değişikliğini veri katmanına bildirir. 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&#39;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 bunların 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 şartları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. İşletme mantığı genellikle alan veya veri katmanlarına yerleştirilir ancak hiçbir zaman kullanıcı arayüzü katmanına 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 kısa ileti ya da snackbar kullanarak ekranda kullanıcı mesajı gösterme.

Kullanıcı arayüzü mantığını, özellikle Context gibi kullanıcı arayüzü türlerini içerdiğinde ViewModel'de değil, kullanıcı arayüzünde tutun. Kullanıcı arayüzü karmaşıklaştıysa 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 istiyorsanız durum bilgisi depolayıcı 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 nihai olarak kullanıldığı yeri de ayırı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üleme ve bu değişiklikleri ViewModel'e ileterek kullanıcı niyetini aktarma.

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 bir veri 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 bilgisi depolayıcının 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 kolaydı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, private set ile mutableStateOf özelliği 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 gerçekleştirmeniz gereken durumu ele alalım. viewModelScope kullanarak bir eş yordam 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 girişimin 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ş mantıkları kaynakların bir kombinasyonunu gerektirebilir. Örneğin, yer işareti düğmesini yalnızca kullanıcının oturum açması ve 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 mülkten türetilmiş bir mülktür. İş mantığı daha karmaşık hale geldikçe 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 akış mı yoksa birden fazla akış mı? Kullanıcı arayüzü durumunu tek bir akışta mı yoksa birden fazla akışta mı göstereceğinizi seçerken temel olarak, yayınlanan öğeler arasındaki ilişkiyi göz önünde bulundurmanız gerekir. Tek akışlı bir gösterimin en büyük avantajları kolaylık ve veri tutarlılığıdır: Durum tüketicileri, her zaman en son bilgilere erişebilir. Ancak ViewModel'den ayrı durum akışlarının uygun olabileceği durumlar vardır:

    • Alakasız 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 eyaletlerden biri diğerinden daha sık güncelleniyorsa bu farklı durumları bir araya getirmenin maliyeti faydalarından daha fazla olabilir.

    • UiState Farklı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 yayınların farklı mı yoksa aynı mı olduğunu anlamak için bir karşılaştırma mekanizması olmadığından her yayın, kullanıcı arayüzü öğesinde güncellemeye 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 nesne 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. Composable kullanıcıya gösterilmediğinde kullanıcı arayüzünün kullanıcı arayüzü durumunu gözlemlemesini sağlamayın. 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 ile 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

Kullanıcı arayüzünde hataları göstermek, devam eden işlemleri göstermeye benzer. Çünkü her ikisi de varlıklarını veya yokluklarını belirten boolean değerleriyle kolayca temsil edilebilir. Ancak hatalar, kullanıcıya geri iletilecek ilişkili bir mesaj veya başarısız olan 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.

Sayfalama

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, sabit bir tür olmadığından) bunu sabit 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

Sorunsuz üst düzey 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 kılavuzun nasıl uygulandığını görmek için aşağıdaki kaynakları inceleyin: