Durumunuzun nereye yükseltildiğine ve gereken mantığa bağlı olarak kullanıcı arayüzü durumunuzu depolamak ve geri yüklemek için farklı API'ler kullanabilirsiniz. Her uygulama, bunu en iyi şekilde başarmak için API'lerin bir kombinasyonunu kullanır.
Etkinlik veya süreç yeniden oluşturma nedeniyle tüm Android uygulamaları kullanıcı arayüzü durumunu kaybedebilir. Bu durum kaybı aşağıdaki olaylardan kaynaklanabilir:
- Yapılandırma değişiklikleri: Yapılandırma değişikliği manuel olarak işlenmediği sürece etkinlik yok edilir ve yeniden oluşturulur.
- Sistem tarafından başlatılan işlem sonlandırma: Uygulama arka plandadır ve cihaz, diğer işlemler tarafından kullanılmak üzere kaynakları (ör. bellek) boşaltır.
Bu etkinliklerden sonra durumu korumak, olumlu bir kullanıcı deneyimi için çok önemlidir. Hangi durumun kalıcı olacağını seçmek, uygulamanızın benzersiz kullanıcı akışlarına bağlıdır. En iyi uygulama olarak, en azından kullanıcı girişini ve gezinmeyle ilgili durumu korumanız gerekir. Buna örnek olarak bir listenin kaydırma konumu, kullanıcının hakkında daha fazla bilgi edinmek istediği öğenin kimliği, devam eden kullanıcı tercihi seçimi veya metin alanlarına girilen bilgiler verilebilir.
Bu sayfada, durumunuzun yükseltildiği yere ve buna ihtiyaç duyan mantığa bağlı olarak kullanıcı arayüzü durumunu depolamak için kullanılabilecek API'ler özetlenmektedir.
Kullanıcı arayüzü mantığı
Durumunuz, composable işlevlerde veya Oluşturma kapsamlı düz durum bilgisi depolayıcı sınıflarda kullanıcı arayüzünde barındırılıyorsa etkinlik ve süreç yeniden oluşturma işlemleri arasında durumu korumak için rememberSaveable kullanabilirsiniz.
Aşağıdaki snippet'te, tek bir boolean kullanıcı arayüzü öğesi durumunu depolamak için rememberSaveable kullanılır:
@Composable fun ChatBubble( message: Message ) { var showDetails by rememberSaveable { mutableStateOf(false) } ClickableText( text = AnnotatedString(message.content), onClick = { showDetails = !showDetails } ) if (showDetails) { Text(message.timestamp) } }
showDetails, sohbet balonunun daraltılıp daraltılmadığını veya genişletilip genişletilmediğini depolayan bir Boole değişkenidir.
rememberSaveable, kaydedilmiş örnek durumu mekanizması aracılığıyla Bundle içinde kullanıcı arayüzü öğesi durumunu depolar.
Paketteki temel türleri otomatik olarak saklayabilir. Durumunuz, veri sınıfı gibi temel olmayan bir türde tutuluyorsa Parcelize ek açıklamasını kullanma, listSaver ve mapSaver gibi Compose API'lerini kullanma veya Compose çalışma zamanı Saver sınıfını genişleten özel bir kaydedici sınıfı uygulama gibi farklı saklama mekanizmalarını kullanabilirsiniz. Bu yöntemler hakkında daha fazla bilgi edinmek için Durumu saklama yöntemleri dokümanına bakın.
Aşağıdaki snippet'te, rememberLazyListState Compose API, rememberSaveable kullanarak LazyColumn veya LazyRow öğesinin kaydırma durumundan oluşan LazyListState öğesini depolar. Kaydırma durumunu saklayıp geri yükleyebilen özel bir koruyucu olan LazyListState.Saver kullanılır. Etkinlik veya süreç yeniden oluşturulduktan sonra (ör. cihaz yönünü değiştirme gibi bir yapılandırma değişikliğinden sonra) kaydırma durumu korunur.
@Composable fun rememberLazyListState( initialFirstVisibleItemIndex: Int = 0, initialFirstVisibleItemScrollOffset: Int = 0 ): LazyListState { return rememberSaveable(saver = LazyListState.Saver) { LazyListState( initialFirstVisibleItemIndex, initialFirstVisibleItemScrollOffset ) } }
En iyi uygulama
rememberSaveable, kullanıcı arayüzü durumunu depolamak için Bundle kullanır. Bu Bundle, etkinliğinizdeki onSaveInstanceState() çağrıları gibi aynı zamanda bu Bundle'a yazan diğer API'ler tarafından paylaşılır. Ancak bu Bundle'ın boyutu sınırlıdır ve büyük nesnelerin depolanması, çalışma zamanında TransactionTooLarge istisnalarına yol açabilir. Bu durum, özellikle aynı Bundle'ın uygulama genelinde kullanıldığı tek Activity uygulamalarda sorun yaratabilir.
Bu tür bir kilitlenmeyi önlemek için pakette büyük ve karmaşık nesneler veya nesne listeleri depolamamalısınız.
Bunun yerine, gereken minimum durumu (ör. kimlikler veya anahtarlar) depolayın ve bunları kullanarak daha karmaşık kullanıcı arayüzü durumunu geri yükleme işlemini kalıcı depolama gibi diğer mekanizmalara devredin.
Bu tasarım tercihleri, uygulamanızın kullanım alanlarına ve kullanıcılarınızın uygulamadan beklentilerine bağlıdır.
Durum geri yüklemeyi doğrulama
Etkinlik veya süreç yeniden oluşturulduğunda, rememberSaveable ile depolanan durumun Compose öğelerinizde doğru şekilde geri yüklendiğini doğrulayabilirsiniz. Bunu yapmak için StateRestorationTester gibi belirli API'ler vardır. Daha fazla bilgi edinmek için Test belgelerine göz atın.
İş mantığı
Kullanıcı arayüzü öğesi durumunuz, iş mantığı tarafından gerekli olduğu için ViewModel'ye yükseltilmişse ViewModel'nin API'lerini kullanabilirsiniz.
Android uygulamanızda ViewModel kullanmanın temel avantajlarından biri, yapılandırma değişikliklerini ücretsiz olarak işlemesidir. Yapılandırma değişikliği olduğunda ve etkinlik yok edilip yeniden oluşturulduğunda, ViewModel'ya yükseltilen kullanıcı arayüzü durumu bellekte tutulur. Yeniden oluşturma işleminden sonra eski ViewModel
örneği, yeni etkinlik örneğine eklenir.
Ancak ViewModel örneği, sistem tarafından başlatılan süreç sonlandırmadan etkilenmez.
Kullanıcı arayüzü durumunun bundan etkilenmemesi için SavedStateHandle API'sini içeren ViewModel için Kayıtlı Durum modülünü kullanın.
En iyi uygulama
SavedStateHandle, kullanıcı arayüzü durumunu depolamak için Bundle mekanizmasını da kullanır. Bu nedenle, yalnızca basit kullanıcı arayüzü öğesi durumunu depolamak için kullanmalısınız.
İşletme kuralları uygulanarak ve kullanıcı arayüzü dışındaki uygulama katmanlarına erişilerek oluşturulan ekran kullanıcı arayüzü durumu, karmaşıklığı ve boyutu nedeniyle SavedStateHandle içinde depolanmamalıdır. Karmaşık veya büyük verileri depolamak için yerel kalıcı depolama gibi farklı mekanizmalar kullanabilirsiniz. Süreç yeniden oluşturulduktan sonra ekran, SavedStateHandle içinde depolanan geçici durum geri yüklenerek yeniden oluşturulur (varsa) ve ekran kullanıcı arayüzü durumu, veri katmanından tekrar oluşturulur.
SavedStateHandle API'ler
SavedStateHandle, kullanıcı arayüzü öğesi durumunu depolamak için farklı API'lere sahiptir. Bunlardan en önemlileri:
Oluştur State |
saveable() |
|---|---|
StateFlow |
getStateFlow() |
Oluştur State
Kullanıcı arayüzü öğesi durumunu MutableState olarak okumak ve yazmak için saveable API'sini kullanın. Böylece, etkinlik ve süreç yeniden oluşturma işlemi en az kod kurulumuyla gerçekleştirilir.SavedStateHandle
saveable API, kullanıma hazır olarak temel türleri destekler ve rememberSaveable() gibi özel kaydedicileri kullanmak için stateSaver parametresini alır.
Aşağıdaki snippet'te message, bir TextField içine yazılan kullanıcı girişini saklar:
class ConversationViewModel( savedStateHandle: SavedStateHandle ) : ViewModel() { var message by savedStateHandle.saveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } private set fun update(newMessage: TextFieldValue) { message = newMessage } /*...*/ } val viewModel = ConversationViewModel(SavedStateHandle()) @Composable fun UserInput(/*...*/) { TextField( value = viewModel.message, onValueChange = { viewModel.update(it) } ) }
saveable API'yi kullanma hakkında daha fazla bilgi için SavedStateHandle belgelerine bakın.
StateFlow
Kullanıcı arayüzü öğesi durumunu depolamak ve SavedStateHandle öğesinden akış olarak kullanmak için getStateFlow() öğesini kullanın. StateFlow salt okunurdur ve API, akışı yeni bir değer yayacak şekilde değiştirebilmeniz için bir anahtar belirtmenizi gerektirir. Yapılandırdığınız anahtarla StateFlow değerini alabilir ve en son değeri toplayabilirsiniz.
Aşağıdaki snippet'te savedFilterType, bir sohbet uygulamasındaki sohbet kanalları listesine uygulanan filtre türünü depolayan bir StateFlow değişkendir:
private const val CHANNEL_FILTER_SAVED_STATE_KEY = "ChannelFilterKey" class ChannelViewModel( channelsRepository: ChannelsRepository, private val savedStateHandle: SavedStateHandle ) : ViewModel() { private val savedFilterType: StateFlow<ChannelsFilterType> = savedStateHandle.getStateFlow( key = CHANNEL_FILTER_SAVED_STATE_KEY, initialValue = ChannelsFilterType.ALL_CHANNELS ) private val filteredChannels: Flow<List<Channel>> = combine(channelsRepository.getAll(), savedFilterType) { channels, type -> filter(channels, type) }.onStart { emit(emptyList()) } fun setFiltering(requestType: ChannelsFilterType) { savedStateHandle[CHANNEL_FILTER_SAVED_STATE_KEY] = requestType } /*...*/ } enum class ChannelsFilterType { ALL_CHANNELS, RECENT_CHANNELS, ARCHIVED_CHANNELS }
Kullanıcı her yeni filtre türü seçtiğinde setFiltering çağrılır. Bu işlem, _CHANNEL_FILTER_SAVED_STATE_KEY_ anahtarıyla saklanan SavedStateHandle içinde yeni bir değer kaydeder. savedFilterType, anahtarda depolanan en son değeri yayan bir akıştır. filteredChannels, kanal filtreleme işlemini gerçekleştirmek için akışa abone olmalıdır.
getStateFlow() API hakkında daha fazla bilgi için SavedStateHandle belgelerine bakın.
Özet
Aşağıdaki tabloda, bu bölümde ele alınan API'ler ve kullanıcı arayüzü durumunu kaydetmek için her birinin ne zaman kullanılacağı özetlenmiştir:
| Etkinlik | Kullanıcı arayüzü mantığı | ViewModel içindeki iş mantığı |
|---|---|---|
| Yapılandırma değişiklikleri | rememberSaveable |
Otomatik |
| Sistem tarafından başlatılan işlem sonlandırma | rememberSaveable |
SavedStateHandle |
Kullanılacak API, durumun nerede tutulduğuna ve gerektirdiği mantığa bağlıdır. Kullanıcı arayüzü mantığında kullanılan durum için rememberSaveable kullanın. İş mantığında kullanılan durum için, durumu ViewModel içinde tutuyorsanız SavedStateHandle kullanarak kaydedin.
Küçük miktarlardaki kullanıcı arayüzü durumunu depolamak için paket API'lerini (rememberSaveable ve SavedStateHandle) kullanmanız gerekir. Bu veriler, kullanıcı arayüzünü önceki durumuna geri yüklemek için diğer depolama mekanizmalarıyla birlikte gereken minimum verilerdir. Örneğin, kullanıcının baktığı bir profilin kimliğini pakette depolarsanız profil ayrıntıları gibi ağır verileri veri katmanından getirebilirsiniz.
Kullanıcı arayüzü durumunu kaydetmenin farklı yolları hakkında daha fazla bilgi için genel Kullanıcı Arayüzü Durumunu Kaydetme belgeleri ile mimari kılavuzun veri katmanı sayfasına bakın.
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir.
- Durumu nerede gösterebilirsiniz?
- Durum ve Jetpack Compose
- Listeler ve ızgaralar