Eyalet sahipleri ve kullanıcı arayüzü durumu

Kullanıcı arayüzü katmanı kılavuzunda, kullanıcı arayüzü katmanı için Kullanıcı Arayüzü Durumunu oluşturma ve yönetme yöntemi olarak tek yönlü veri akışı (UDF) ele alınmaktadır.

Veri, veri katmanından kullanıcı arayüzüne tek yönlü olarak akar.
Şekil 1: Tek Yönlü veri akışı

Ayrıca, UDF yönetiminde devlet sahibi adı verilen özel bir sınıfa yetki vermenin avantajları da vurgulanmaktadır. Eyalet sahibini ViewModel veya düz sınıf aracılığıyla uygulayabilirsiniz. Bu belgede, durum sahiplerine ve kullanıcı arayüzü katmanında oynadıkları role daha yakından bakılmıştır.

Bu belgenin sonunda, uygulama durumunun kullanıcı arayüzü katmanında, yani kullanıcı arayüzü durumu üretim ardışık düzeninde nasıl yönetileceğini öğrenmiş olmanız gerekir. Aşağıdakileri anlayabilmeniz ve bilmeniz gerekir:

  • Kullanıcı arayüzü katmanındaki kullanıcı arayüzü durumu türlerini anlayın.
  • Kullanıcı arayüzü katmanındaki bu kullanıcı arayüzü durumlarında çalışan mantık türlerini anlayın.
  • ViewModel veya basit sınıf gibi bir eyalet sahibinin uygun uygulamasını nasıl seçeceğinizi öğrenin.

Kullanıcı arayüzü durumu üretim ardışık düzeninin öğeleri

Kullanıcı arayüzü durumu ve bunu oluşturan mantık, kullanıcı arayüzü katmanını tanımlar.

Kullanıcı arayüzü durumu

Kullanıcı arayüzü durumu, kullanıcı arayüzünü açıklayan özelliktir. İki tür kullanıcı arayüzü durumu vardır:

  • Ekran kullanıcı arayüzü durumu, ekranda görüntülemeniz gereken şeydir. Örneğin, bir NewsUiState sınıfı, kullanıcı arayüzünü oluşturmak için gereken haber makalelerini ve diğer bilgileri içerebilir. Bu durum, uygulama verilerini içerdiği için genellikle hiyerarşinin diğer katmanlarıyla bağlantılıdır.
  • Kullanıcı arayüzü öğesi durumu, oluşturulma şeklini etkileyen kullanıcı arayüzü öğelerinde bulunan özellikleri ifade eder. Bir kullanıcı arayüzü öğesi gösterilebilir veya gizlenebilir ve belirli bir yazı tipi, yazı tipi boyutu veya yazı tipi rengine sahip olabilir. Android Görünümlerinde Görünüm, doğası gereği durum bilgili olduğundan durumu değiştirme veya sorgulama yöntemleri sunduğu için bu durumu yönetir. Bunun örneği, metni için TextView sınıfının get ve set yöntemleridir. Jetpack Compose'da durum, oluşturulabilecek olanın dışındadır ve hatta bile oluşturma işlemini, oluşturulabilir öğenin yakın yakınından, çağıran birleştirilebilir işleve veya bir durum sahibine gönderebilirsiniz. Scaffold composable için ScaffoldState buna örnek olarak verilebilir.

Mantık

Uygulama verileri ve kullanıcı etkinlikleri, kullanıcı arayüzü durumunun zaman içinde değişmesine neden olduğundan kullanıcı arayüzü durumu statik bir mülk değildir. Kullanıcı arayüzü durumunun hangi bölümlerinin değiştiği, neden değiştiği ve ne zaman değişmesi gerektiği de dahil olmak üzere değişikliğin ayrıntılarını mantık belirler.

Mantık, kullanıcı arayüzü durumu üretir
Şekil 2: Kullanıcı arayüzü durumunun üreticisi olarak mantık

Bir uygulamanın mantığı, iş mantığı veya kullanıcı arayüzü mantığı olabilir:

  • İş mantığı, uygulama verileri için ürün gereksinimlerinin uygulanmasıdır. Örneğin, kullanıcı düğmeye dokunduğunda haber okuyucu uygulamasında bir makaleye yer işareti koyma. Bir dosyaya veya veritabanına yer işareti kaydetme mantığı, genellikle alana veya veri katmanlarına yerleştirilir. Durum sorumlusu, genellikle ortaya koydukları yöntemleri çağırarak bu mantığı bu katmanlara devreder.
  • Kullanıcı arayüzü mantığı, ekranda kullanıcı arayüzü durumunun nasıl gösterileceğiyle ilgilidir. Örneğin, kullanıcı bir kategori seçtiğinde doğru arama çubuğu ipucunun elde edilmesi, bir listedeki belirli bir öğeye kaydırılması veya kullanıcı bir düğmeyi tıkladığında gezinme mantığının belirli bir ekrana gelmesi.

Android yaşam döngüsü, kullanıcı arayüzü durumu ve mantığının türleri

Kullanıcı arayüzü katmanının iki bölümü vardır: Biri kullanıcı arayüzü yaşam döngüsünden bağımsız, diğeri bağımlı. Bu ayırma, her bir parça için kullanılabilen veri kaynaklarını belirlediğinden farklı türde kullanıcı arayüzü durumu ve mantık gerektirir.

  • Kullanıcı arayüzü yaşam döngüsünden bağımsız: Kullanıcı arayüzü katmanının bu bölümü, uygulamanın veri oluşturma katmanlarıyla (veri veya alan katmanları) ilgilidir ve iş mantığıyla tanımlanır. Kullanıcı arayüzündeki yaşam döngüsü, yapılandırma değişiklikleri ve Activity yeniden oluşturma işlemleri, kullanıcı arayüzü durumu üretim hattının etkin olup olmadığını etkileyebilir ancak üretilen verilerin geçerliliğini etkilemez.
  • Kullanıcı arayüzü yaşam döngüsüne bağlı: Kullanıcı arayüzü katmanının bu bölümü, kullanıcı arayüzü mantığıyla ilgilidir ve yaşam döngüsünden veya yapılandırma değişikliklerinden doğrudan etkilenir. Bu değişiklikler, içerisinde okunan veri kaynaklarının geçerliliğini doğrudan etkiler ve dolayısıyla durumu yalnızca yaşam döngüsü aktif olduğunda değişebilir. Çalışma zamanı izinleri ve yerelleştirilmiş dizeler gibi yapılandırmaya bağlı kaynakları alma, buna örnek olarak gösterilebilir.

Yukarıda belirtilenler, aşağıdaki tabloyla özetlenebilir:

Kullanıcı Arayüzü Yaşam Döngüsü Bağımsız Kullanıcı Arayüzü Yaşam Döngüsüne bağımlı
İş mantığı Kullanıcı Arayüzü Mantığı
Ekran kullanıcı arayüzü durumu

Kullanıcı arayüzü durumu üretim ardışık düzeni

Kullanıcı arayüzü durumu üretim ardışık düzeni, kullanıcı arayüzü durumu üretmek için gerçekleştirilen adımları ifade eder. Bu adımlar, daha önce tanımlanan mantık türlerinin uygulanmasından oluşur ve tamamen kullanıcı arayüzünüzün ihtiyaçlarına bağlıdır. Bazı kullanıcı arayüzleri, ardışık düzenin hem Kullanıcı Arayüzü Yaşam Döngüsünden hem de Kullanıcı Arayüzü Yaşam Döngüsü'ne bağlı bölümlerinden yararlanabilir veya hiçbirinden fayda sağlamayabilir.

Yani kullanıcı arayüzü katmanı ardışık düzeninin aşağıdaki permütasyonları geçerlidir:

  • Kullanıcı arayüzünün kendisi tarafından üretilen ve yönetilen kullanıcı arayüzü durumu. Örneğin, basit ve yeniden kullanılabilir bir temel sayaç:

    @Composable
    fun Counter() {
        // The UI state is managed by the UI itself
        var count by remember { mutableStateOf(0) }
        Row {
            Button(onClick = { ++count }) {
                Text(text = "Increment")
            }
            Button(onClick = { --count }) {
                Text(text = "Decrement")
            }
        }
    }
    
  • Kullanıcı arayüzü mantığı → Kullanıcı arayüzü. Örneğin, kullanıcının listenin en üstüne atlamasına olanak tanıyan bir düğmeyi gösterme veya gizleme.

    @Composable
    fun ContactsList(contacts: List<Contact>) {
        val listState = rememberLazyListState()
        val isAtTopOfList by remember {
            derivedStateOf {
                listState.firstVisibleItemIndex < 3
            }
        }
    
        // Create the LazyColumn with the lazyListState
        ...
    
        // Show or hide the button (UI logic) based on the list scroll position
        AnimatedVisibility(visible = !isAtTopOfList) {
            ScrollToTopButton()
        }
    }
    
  • İş mantığı → kullanıcı arayüzü. Ekranda geçerli kullanıcının fotoğrafını gösteren bir kullanıcı arayüzü öğesi.

    @Composable
    fun UserProfileScreen(viewModel: UserProfileViewModel = hiltViewModel()) {
        // Read screen UI state from the business logic state holder
        val uiState by viewModel.uiState.collectAsStateWithLifecycle()
    
        // Call on the UserAvatar Composable to display the photo
        UserAvatar(picture = uiState.profilePicture)
    }
    
  • İş mantığı → kullanıcı arayüzü mantığı → kullanıcı arayüzü. Belirli bir kullanıcı arayüzü durumu için ekranda doğru bilgileri görüntülemek üzere kayan bir kullanıcı arayüzü öğesidir.

    @Composable
    fun ContactsList(viewModel: ContactsViewModel = hiltViewModel()) {
        // Read screen UI state from the business logic state holder
        val uiState by viewModel.uiState.collectAsStateWithLifecycle()
        val contacts = uiState.contacts
        val deepLinkedContact = uiState.deepLinkedContact
    
        val listState = rememberLazyListState()
    
        // Create the LazyColumn with the lazyListState
        ...
    
        // Perform UI logic that depends on information from business logic
        if (deepLinkedContact != null && contacts.isNotEmpty()) {
            LaunchedEffect(listState, deepLinkedContact, contacts) {
                val deepLinkedContactIndex = contacts.indexOf(deepLinkedContact)
                if (deepLinkedContactIndex >= 0) {
                  // Scroll to deep linked item
                  listState.animateScrollToItem(deepLinkedContactIndex)
                }
            }
        }
    }
    

Kullanıcı arayüzü durumu üretim ardışık düzenine her iki tür mantığın da uygulandığı durumlarda, iş mantığı her zaman kullanıcı arayüzü mantığından önce uygulanmalıdır. Kullanıcı arayüzü mantığından sonra iş mantığını uygulamaya çalışmak, iş mantığının kullanıcı arayüzü mantığına bağlı olduğu anlamına gelir. Bunun neden bir sorun olduğu, farklı mantık türlerine ve durum sahiplerine ayrıntılı bir şekilde değinilerek aşağıdaki bölümlerde ele alınmaktadır.

Veri üreten katmandan kullanıcı arayüzüne veri akışı
Şekil 3: Kullanıcı arayüzü katmanında mantığın uygulanması

Devlet sahipleri ve sorumlulukları

Eyalet sahibinin sorumluluğu, uygulamanın okuyabilmesi için durumu depolamaktır. Mantığın gerekli olduğu durumlarda aracı görevi görür ve gerekli mantığı barındıran veri kaynaklarına erişim sağlar. Bu şekilde durum sahibi, mantığı uygun veri kaynağına yetkilendirir.

Bunun sonucunda şu avantajlar elde edilir:

  • Basit kullanıcı arayüzleri: Kullanıcı arayüzü yalnızca durumunu bağlar.
  • Sürdürülebilirlik: Durum sahibinde tanımlanan mantık, kullanıcı arayüzünün kendisi değiştirilmeden yinelenebilir.
  • Test edilebilirlik: Kullanıcı arayüzü ve durum üretim mantığı bağımsız olarak test edilebilir.
  • Okunabilirlik: Kodu okuyanlar, kullanıcı arayüzü sunu kodu ile kullanıcı arayüzü durumu üretim kodu arasındaki farklılıkları net bir şekilde görebilir.

Boyutu veya kapsamı ne olursa olsun her kullanıcı arayüzü öğesinin, karşılık gelen durum sahibiyle 1:1 bir ilişkisi vardır. Ayrıca durum sahibi, kullanıcı arayüzü durum değişikliğine neden olabilecek tüm kullanıcı işlemlerini kabul edip işleyebilmeli ve sonraki durum değişikliğini üretmelidir.

Devlet sahibi türleri

Kullanıcı arayüzü durum ve mantık türlerine benzer şekilde, kullanıcı arayüzü katmanında, kullanıcı arayüzü yaşam döngüsüyle olan ilişkilerine göre tanımlanan iki tür durum sahibi vardır:

  • İş mantığı durum sahibi.
  • Kullanıcı arayüzü mantık durumu tutucusu.

Aşağıdaki bölümlerde, iş mantığı durum sahibinden başlayarak devlet sahiplerinin türlerine daha yakından bakılmaktadır.

İş mantığı ve durum bilgisi

İş mantığı durum sahipleri, kullanıcı etkinliklerini işler ve verileri veri veya alan katmanlarından ekran kullanıcı arayüzü durumuna dönüştürür. Android yaşam döngüsü ve uygulama yapılandırması değişikliklerini göz önünde bulundururken optimum kullanıcı deneyimi sunmak için iş mantığından yararlanan devlet sahiplerinin aşağıdaki özelliklere sahip olması gerekir:

Özellik Ayrıntı
Kullanıcı Arayüzü Durumunu oluşturur İş mantığı durum sahipleri, kullanıcı arayüzleri için kullanıcı arayüzü durumlarını oluşturmaktan sorumludur. Bu kullanıcı arayüzü durumu, genellikle kullanıcı etkinliklerinin işlenmesinin ve alandan ve veri katmanlarından gelen verilerin okunmasından kaynaklanır.
Etkinlik rekreasyon aracılığıyla elde tutulur İş mantığı durum sahipleri, Activity yeniden oluşturma genelinde durum ve durum işleme ardışık düzenlerini koruyarak sorunsuz bir kullanıcı deneyimi sunmaya yardımcı olur. Devlet sahibinin saklanması mümkün olmadığı ve yeniden oluşturulduğu durumlarda (genellikle işlem ölümünden sonra) tutarlı bir kullanıcı deneyimi sağlamak için son durumunu kolayca yeniden oluşturabilmelidir.
Uzun ömürlü duruma sahip olma İş mantığı durum sahipleri, genellikle navigasyon hedefleri için durumu yönetmek amacıyla kullanılır. Bunun sonucunda, gezinme grafiğinden kaldırılana kadar gezinme değişikliklerindeki durumlarını genellikle korurlar.
Kullanıcı arayüzüne özgü olmalıdır ve yeniden kullanılamaz İş mantığı durum sahipleri, genellikle TaskEditViewModel veya TaskListViewModel gibi belirli bir uygulama işlevi için durum oluşturur ve bu nedenle, yalnızca bu uygulama işlevi için geçerli olur. Aynı durum sahibi, bu uygulama işlevlerini farklı form faktörlerinde destekleyebilir. Örneğin, uygulamanın mobil, TV ve tablet sürümleri aynı iş mantığı durum sahibini yeniden kullanabilir.

Örneğin, "Now in Android" uygulamasındaki yazar gezinme hedefini ele alalım:

Android&#39;de Now uygulaması, önemli bir uygulama işlevini temsil eden gezinme hedefinin kendi benzersiz iş mantığı durum sahibine nasıl sahip olması gerektiğini gösterir.
Şekil 4: Now in Android uygulaması

İş mantığı durum sahibi olarak hareket eden AuthorViewModel, bu durumda kullanıcı arayüzü durumunu oluşturur:

@HiltViewModel
class AuthorViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle,
    private val authorsRepository: AuthorsRepository,
    newsRepository: NewsRepository
) : ViewModel() {

    val uiState: StateFlow<AuthorScreenUiState> = …

    // Business logic
    fun followAuthor(followed: Boolean) {
      …
    }
}

AuthorViewModel öğesinin daha önce açıklanan özelliklere sahip olduğuna dikkat edin:

Özellik Ayrıntı
AuthorScreenUiState üretir AuthorViewModel, AuthorsRepository ve NewsRepository verilerindeki verileri okur ve bu verileri AuthorScreenUiState üretmek için kullanır. Kullanıcı, AuthorsRepository için yetki vererek bir Author öğesini takip etmek veya takibi bırakmak istediğinde iş mantığını da uygular.
Veri katmanına erişimi var AuthorsRepository ve NewsRepository örnekleri, oluşturucuda kendisine iletilir ve bu sayede Author izleme iş mantığını uygulayabilir.
Activity etkinlik sırasında hayatta kalır ViewModel ile uygulandığından hızlı Activity yeniden oluşturma işleminde tutulur. İşlemin ölmesi durumunda, kullanıcı arayüzü durumunu veri katmanından geri yüklemek için gereken minimum bilgi miktarını sağlamak üzere SavedStateHandle nesnesi şuradan okunabilir:
Uzun ömürlü duruma sahip ViewModel, gezinme grafiğinin kapsamındadır. Bu nedenle, yazar hedefi gezinme grafiğinden kaldırılmadığı sürece uiState StateFlow içindeki kullanıcı arayüzü durumu bellekte kalır. StateFlow kullanımı, durumu tembel oluşturan iş mantığının uygulanmasının avantajını da ekler. Bunun nedeni, yalnızca kullanıcı arayüzü durumu bir toplayıcısı durumunda durum üretilmesidir.
Kullanıcı arayüzüne özgü olmalıdır AuthorViewModel yalnızca yazarın gezinme hedefi için geçerlidir ve başka hiçbir yerde yeniden kullanılamaz. Gezinme hedeflerinde yeniden kullanılan bir iş mantığı varsa bu iş mantığının veri veya alan katmanı kapsamlı bir bileşene dahil edilmesi gerekir.

İş mantığı durum sahibi olarak ViewModel

Android geliştirmedeki ViewModels, bunları iş mantığına erişim ve uygulama verilerini ekranda sunum için hazırlamaya uygun hale getirir. Bu avantajlardan bazıları şunlardır:

  • ViewModels tarafından tetiklenen işlemler yapılandırma değişikliklerini atlatmaya devam eder.
  • Gezinme ile entegrasyon:
    • Gezinme, ekran arka yığındayken ViewModel'leri önbelleğe alır. Daha önce yüklediğiniz verilerin hedefinize geri döndüğünüzde anında kullanılabilir olması önemlidir. Oluşturulabilir ekranın yaşam döngüsünü takip eden bir eyalet sahibi için bunu yapmanın daha zor bir yolu olduğunu söyleyebiliriz.
    • ViewModel, hedef arka yığından çıkarıldığında da temizlenir. Böylece durum otomatik olarak temizlenir. Bu, yapılandırma değişikliği veya başka nedenlerle yeni bir ekrana gitme gibi birden çok nedenden dolayı oluşturulabilecek bir araya getirilmesini dinlemeden farklıdır.
  • Hilt gibi diğer Jetpack kitaplıklarıyla entegrasyon.

Kullanıcı arayüzü mantığı ve durum koruyucu

Kullanıcı arayüzü mantığı, kullanıcı arayüzünün sağladığı veriler üzerinde çalışan bir mantıktır. Bu, kullanıcı arayüzü öğelerinin durumunda veya izinler API'si ya da Resources gibi kullanıcı arayüzü veri kaynaklarında olabilir. Kullanıcı arayüzü mantığını kullanan durum sahipleri genellikle aşağıdaki özelliklere sahiptir:

  • Kullanıcı arayüzü durumunu oluşturur ve kullanıcı arayüzü öğelerinin durumunu yönetir.
  • Activity yeniden oluşturmasından sonra dayanmaz: Kullanıcı arayüzü mantığında barındırılan eyalet sahipleri, genellikle kullanıcı arayüzünün kendisinden gelen veri kaynaklarına bağımlıdır ve bu bilgileri yapılandırma değişiklikleri genelinde saklamaya çalışmak, bellek sızıntısına neden olmamasından daha sıktır. Devlet sahiplerinin yapılandırma değişiklikleri boyunca değişmeleri için verilerin korunmasını istemeleri durumunda, Activity rekreasyonunda hayatta kalmak için başka bir bileşene yetki vermeleri gerekir. Örneğin Jetpack Compose'da remembered işlevleriyle oluşturulan yazılabilir kullanıcı arayüzü öğe durumları genellikle Activity yeniden oluşturma genelinde durumu korumak için rememberSaveable'ye yetki verir. Bu tür işlevlere örnek olarak rememberScaffoldState() ve rememberLazyListState() verilebilir.
  • Kullanıcı arayüzü kapsamlı veri kaynaklarına referans içeriyor: Kullanıcı arayüzü mantık durumu sahibi, kullanıcı arayüzü ile aynı yaşam döngüsüne sahip olduğundan yaşam döngüsü API'leri ve Kaynaklar gibi veri kaynaklarına güvenli bir şekilde referans verilebilir ve bu kaynaklar okunabilir.
  • Birden çok kullanıcı arayüzünde yeniden kullanılabilir: Aynı kullanıcı arayüzü mantığı durum sahibinin farklı örnekleri, uygulamanın farklı bölümlerinde yeniden kullanılabilir. Örneğin, bir çip grubuna ilişkin kullanıcı girişi etkinliklerini yönetmek için bir durum sahibi, filtre çiplerinin arama sayfasında ve ayrıca e-posta alıcıları için "alıcı" alanı için kullanılabilir.

Kullanıcı arayüzü mantık durumu tutucusu genellikle düz bir sınıfla uygulanır. Bunun nedeni, kullanıcı arayüzü mantıksal durum sahibinin oluşturulmasından kullanıcı arayüzünün sorumlu olması ve kullanıcı arayüzü mantık durumu sahibinin, kullanıcı arayüzüyle aynı yaşam döngüsüne sahip olmasıdır. Örneğin Jetpack Compose'da eyalet sahibi Bestenin bir parçasıdır ve Beste'nin yaşam döngüsünü izler.

Yukarıdaki bu, Now in Android örneğinde aşağıdaki örnekte belirtilebilir:

Artık Android&#39;de, kullanıcı arayüzü mantığını yönetmek için düz sınıf durum tutucu kullanılıyor
Şekil 5: Now in Android örnek uygulaması

Android'de Now örneğinde, cihazın ekran boyutuna bağlı olarak gezinme için alt uygulama çubuğu veya gezinme çubuğu gösterilmektedir. Küçük ekranlarda alt uygulama çubuğu, daha büyük ekranlarda ise gezinme çubuğu kullanılır.

NiaApp oluşturulabilir işlevinde kullanılan uygun gezinme kullanıcı arayüzü öğesine karar verme mantığı iş mantığına bağlı olmadığından, bu öğe NiaAppState adlı bir düz sınıf durum sahibi tarafından yönetilebilir:

@Stable
class NiaAppState(
    val navController: NavHostController,
    val windowSizeClass: WindowSizeClass
) {

    // UI logic
    val shouldShowBottomBar: Boolean
        get() = windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact ||
            windowSizeClass.heightSizeClass == WindowHeightSizeClass.Compact

    // UI logic
    val shouldShowNavRail: Boolean
        get() = !shouldShowBottomBar

   // UI State
    val currentDestination: NavDestination?
        @Composable get() = navController
            .currentBackStackEntryAsState().value?.destination

    // UI logic
    fun navigate(destination: NiaNavigationDestination, route: String? = null) { /* ... */ }

     /* ... */
}

Yukarıdaki örnekte, NiaAppState ile ilgili aşağıdaki ayrıntılar dikkat çekicidir:

  • Activity yeniden oluşturma işleminden sonra da kalamaz: NiaAppState, Oluşturma adlandırma kurallarına uygun bir Oluşturulabilir işlev rememberNiaAppState ile oluşturduğu için Beste'de remembered değerine sahiptir. Activity yeniden oluşturulduktan sonra önceki örnek kaybedilir ve tüm bağımlılıklarının aktarıldığı yeni bir örnek oluşturulur. Bu örnek, yeniden oluşturulan Activity öğesinin yeni yapılandırmasına uygun olur. Bu bağımlılıklar yeni olabilir veya önceki yapılandırmadan geri yüklenmiş olabilir. Örneğin rememberNavController(), NiaAppState oluşturucuda kullanılır ve Activity yeniden oluşturmasında durumu korumak için rememberSaveable öğesine yetki verir.
  • Kullanıcı arayüzü kapsamlı veri kaynaklarına referanslar içeriyor: navigationController, Resources ve diğer benzer yaşam döngüsü kapsamlı türlere yapılan referanslar, aynı yaşam döngüsü kapsamını paylaştıkları için NiaAppState içinde güvenli bir şekilde barındırılabilir.

Eyalet sahibi için ViewModel ve düz sınıf arasından seçim yapın

Yukarıdaki bölümlerde, ViewModel ile düz sınıf durum sahibi arasında seçim yapmak, kullanıcı arayüzü durumuna uygulanan mantığa ve mantığın üzerinde çalıştığı veri kaynaklarına bağlıdır.

Özet olarak, aşağıdaki şemada devlet sahiplerinin kullanıcı arayüzü durum üretim hattındaki konumu gösterilmektedir:

Veri üreten katmandan kullanıcı arayüzü katmanına veri akışı
Şekil 6: Kullanıcı arayüzü durumu üretim hattındaki eyalet sahipleri. Oklar veri akışını ifade ediyor.

Sonuç olarak, kullanıcı arayüzü durumlarını, tüketildiği yere en yakın eyalet sahiplerini kullanarak üretmelisiniz. Daha az resmi bir şekilde, uygun sahipliği sürdürürken eyaleti mümkün olduğunca düşük tutmalısınız. İş mantığına erişmeniz ve kullanıcı arayüzü durumunun, Activity yeniden pazarlamasında bile bir ekrana gidilebildiği sürece kalıcı olması gerekiyorsa ViewModel, iş mantığı durum sahibi uygulamanız için mükemmel bir seçenektir. Daha kısa ömürlü kullanıcı arayüzü durumu ve kullanıcı arayüzü mantığı için yaşam döngüsü yalnızca kullanıcı arayüzüne bağlı olan düz bir sınıf yeterli olacaktır.

Eyalet sahipleri birleştirilmiştir

Bağımlılıkların süresi eşit veya daha kısa olduğu sürece devlet sahipleri başka devlet sahiplerine bağımlı olabilirler. Buna örnek olarak aşağıdakiler gösterilebilir:

  • bir kullanıcı arayüzü mantık durumu tutucusu, başka bir kullanıcı arayüzü mantık durumu sahibine bağlı olabilir.
  • ekran düzeyinde durum tutucu, kullanıcı arayüzü mantık durumu tutucusuna bağlı olabilir.

Aşağıdaki kod snippet'inde, Compose DrawerState işlevinin başka bir dahili durum sahibine (SwipeableState) nasıl bağlı olduğu ve bir uygulamanın kullanıcı arayüzü mantık durumu sahibinin DrawerState öğesine nasıl bağlı olabileceği gösterilmektedir:

@Stable
class DrawerState(/* ... */) {
  internal val swipeableState = SwipeableState(/* ... */)
  // ...
}

@Stable
class MyAppState(
  private val drawerState: DrawerState,
  private val navController: NavHostController
) { /* ... */ }

@Composable
fun rememberMyAppState(
  drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
  navController: NavHostController = rememberNavController()
): MyAppState = remember(drawerState, navController) {
  MyAppState(drawerState, navController)
}

Durum sahibini aşan bağımlılığa örnek olarak, ekran seviyesi durum sahibine bağlı bir kullanıcı arayüzü mantık durumu sahibi verilebilir. Bu, daha kısa ömürlü durum sahibinin yeniden kullanılabilirliğini azaltır ve gerçekten ihtiyaç duyduğundan daha fazla mantığa ve duruma erişim sağlar.

Daha kısa süreli durum sahibinin daha yüksek kapsamlı bir durum sahibinden belirli bilgilere ihtiyacı varsa durum sahibi örneğini iletmek yerine parametre olarak yalnızca ihtiyacı olan bilgileri iletin. Örneğin, aşağıdaki kod snippet'inde kullanıcı arayüzü mantık durumu tutucu sınıfı, tüm ViewModel örneğini bağımlılık olarak iletmek yerine, tam olarak ihtiyaç duyduğu şeyi ViewModel'den parametre olarak alır.

class MyScreenViewModel(/* ... */) {
  val uiState: StateFlow<MyScreenUiState> = /* ... */
  fun doSomething() { /* ... */ }
  fun doAnotherThing() { /* ... */ }
  // ...
}

@Stable
class MyScreenState(
  // DO NOT pass a ViewModel instance to a plain state holder class
  // private val viewModel: MyScreenViewModel,

  // Instead, pass only what it needs as a dependency
  private val someState: StateFlow<SomeState>,
  private val doSomething: () -> Unit,

  // Other UI-scoped types
  private val scaffoldState: ScaffoldState
) {
  /* ... */
}

@Composable
fun rememberMyScreenState(
  someState: StateFlow<SomeState>,
  doSomething: () -> Unit,
  scaffoldState: ScaffoldState = rememberScaffoldState()
): MyScreenState = remember(someState, doSomething, scaffoldState) {
  MyScreenState(someState, doSomething, scaffoldState)
}

@Composable
fun MyScreen(
  modifier: Modifier = Modifier,
  viewModel: MyScreenViewModel = viewModel(),
  state: MyScreenState = rememberMyScreenState(
    someState = viewModel.uiState.map { it.toSomeState() },
    doSomething = viewModel::doSomething
  ),
  // ...
) {
  /* ... */
}

Aşağıdaki şemada, kullanıcı arayüzü ile önceki kod snippet'inin farklı durum sahipleri arasındaki bağımlılıklar gösterilmektedir:

Hem kullanıcı arayüzü mantık durumu tutucusuna hem de ekran düzeyi durum tutucusuna bağlı olan kullanıcı arayüzü
Şekil 7: Farklı eyalet sahiplerine göre kullanıcı arayüzü. Oklar bağımlılıkları ifade ediyor.

Sana Özel

Aşağıdaki Google örnekleri, kullanıcı arayüzü katmanında eyalet sahiplerinin kullanımını göstermektedir. Bu kılavuzu inceleyerek örnekleri inceleyin: