Bu kılavuzda, kullanıcıların kullanıcı arayüzü durumuyla ilgili beklentileri ve durumu korumak için kullanılabilecek seçenekler ele alınmaktadır.
Sistem, ana makine etkinliğini veya uygulama sürecini yok ettikten sonra kullanıcı arayüzü durumunu hızlı bir şekilde kaydetmek ve geri yüklemek, iyi bir kullanıcı deneyimi için çok önemlidir. Kullanıcılar, kullanıcı arayüzü durumunun aynı kalmasını bekler ancak sistem, ekranı barındıran etkinliği ve depolanmış durumunu yok edebilir.
Kullanıcı beklentileri ile sistem davranışı arasındaki farkı kapatmak için aşağıdaki yöntemlerin bir kombinasyonunu kullanın:
ViewModelnesneler.- Aşağıdaki bağlamlarda kaydedilmiş durum:
- Composable'lar:
rememberSerializableverememberSaveable. - ViewModels:
SavedStateHandle.
- Composable'lar:
- Uygulama ve ekran geçişleri sırasında kullanıcı arayüzü durumunu kalıcı hale getirmek için yerel depolama alanı.
En uygun çözüm, kullanıcı arayüzü verilerinizin karmaşıklığına, uygulamanızın kullanım alanlarına ve veri erişim hızı ile bellek kullanımı arasında bir denge kurmaya bağlıdır.
Uygulamanızın kullanıcıların beklentilerini karşıladığından ve hızlı, duyarlı bir arayüz sunduğundan emin olun. Verileri kullanıcı arayüzüne yüklerken, özellikle döndürme gibi yaygın yapılandırma değişikliklerinden sonra gecikmeleri önleyin.
Kullanıcı beklentileri ve sistem davranışı
Kullanıcının yaptığı işleme bağlı olarak, kullanıcılar kullanıcı arayüzü durumunun temizlenmesini veya korunmasını bekler. Bazı durumlarda sistem, kullanıcının beklentisini karşılayacak şekilde otomatik olarak işlem yapar. Diğer durumlarda ise sistem bunun tam tersini yapar.
Kullanıcı tarafından başlatılan kullanıcı arayüzü durumunu kapatma
Kullanıcı, bir ekrana gittiğinde geçici kullanıcı arayüzü durumunun tamamen kapatılana kadar aynı kalmasını bekler. Kullanıcı, aşağıdaki işlemleri yaparak bir ekranı veya uygulamayı tamamen kapatabilir:
- Uygulamayı Genel Bakış (Son Kullanılanlar) ekranından kaydırarak kapatma
- Uygulamayı Ayarlar ekranından sonlandırma veya kapanmaya zorlama
- Cihazı yeniden başlatma
- Bir tür "tamamlama" işlemini gerçekleştirme (
Activity.finish()tarafından desteklenir).
Kullanıcı, bu tamamen kapatma durumlarında ekrandan kalıcı olarak ayrıldığını varsayar ve geri döndüğünde ekranın temiz bir durumda başlamasını bekler. Bu kapatma senaryolarındaki temel sistem davranışı, kullanıcı beklentisiyle eşleşir. Ana makine etkinliği örneği, içinde depolanan tüm durum ve kendisiyle ilişkili tüm kayıtlı durum kaydıyla birlikte yok edilip bellekten kaldırılır.
Tamamen kapatma ile ilgili bu kuralın bazı istisnaları vardır. Örneğin, bir kullanıcı tarayıcıdan geri düğmesini kullanarak çıkmadan önce baktığı web sayfasına tarayıcının kendisini götürmesini bekleyebilir.
Sistem tarafından başlatılan kullanıcı arayüzü durumunu kapatma
Kullanıcılar, ekran döndürme veya çok pencereli moda geçme gibi yapılandırma değişiklikleri sırasında ekranın kullanıcı arayüzü durumunun aynı kalmasını bekler. Ancak varsayılan olarak sistem, bu tür bir yapılandırma değişikliği gerçekleştiğinde ana makine etkinliğini yok ederek içinde depolanan tüm kullanıcı arayüzü durumunu siler. Cihaz yapılandırmaları hakkında daha fazla bilgi edinmek için Jetpack Compose'da yapılandırma değişikliklerine tepki verme başlıklı makaleyi inceleyin.
Yapılandırma değişiklikleri için varsayılan davranışın geçersiz kılınmasının mümkün olduğunu (ancak önerilmediğini) unutmayın. Daha fazla bilgi için Yapılandırma değişikliğini işleme bölümüne bakın.
Kullanıcılar, geçici olarak farklı bir uygulamaya geçip daha sonra uygulamanıza geri döndüklerinde uygulamanızın kullanıcı arayüzü durumunun aynı kalmasını da bekler. Örneğin, kullanıcı bir ekranda arama yapar, ardından ana sayfa düğmesine basar veya bir telefon görüşmesini yanıtlar. Arama ekranına döndüğünde arama ağı anahtar kelimesinin ve sonuçların, daha önce olduğu gibi orada olmasını bekler.
Bu senaryoda uygulamanız arka plana yerleştirilir ve sistem, uygulama işleminizi bellekte tutmak için elinden geleni yapar. Ancak kullanıcı diğer uygulamalarla etkileşimde bulunurken sistem, uygulama sürecini sonlandırabilir. Bu durumda, ana makine etkinliği ve içinde depolanan tüm durumlar yok edilir. Kullanıcı uygulamayı yeniden başlattığında ekran beklenmedik bir şekilde temiz durumda oluyor. İşlem sonlandırma hakkında daha fazla bilgi edinmek için İşlemler ve uygulama yaşam döngüsü başlıklı makaleyi inceleyin.
Kullanıcı arayüzü durumunu koruma seçenekleri
Kullanıcının kullanıcı arayüzü durumuyla ilgili beklentileri varsayılan sistem davranışıyla eşleşmediğinde, sistem tarafından başlatılan yok etme işleminin kullanıcı için şeffaf olmasını sağlamak amacıyla kullanıcının kullanıcı arayüzü durumunu kaydedip geri yüklemeniz gerekir.
Kullanıcı arayüzü durumunu korumaya yönelik her seçenek, kullanıcı deneyimini etkileyen aşağıdaki boyutlara göre farklılık gösterir:
| ViewModel | Kaydedilmiş durum | Kalıcı depolama alanı | |
|---|---|---|---|
| Depolama konumu | bellek üzerinde | bellek üzerinde | disk veya ağ üzerinde |
| Yapılandırma değişikliğinden etkilenmez | Evet | Evet | Evet |
| Sistem tarafından başlatılan işlem sonlandırmadan etkilenmez. | Hayır | Evet | Evet |
Kullanıcı ekranı tamamen kapattığında/finish() |
Hayır | Hayır | Evet |
| Veri sınırlamaları | Karmaşık nesneler kullanılabilir ancak alan, mevcut bellekle sınırlıdır. | yalnızca temel türler ve String gibi basit, küçük nesneler için |
yalnızca disk alanı veya ağ kaynağındaki alma maliyeti / zamanı ile sınırlıdır. |
| Okuma/yazma süresi | hızlı (yalnızca bellek erişimi) | yavaş (serileştirme/seri durumundan çıkarma gerektirir) | yavaş (disk erişimi veya ağ işlemi gerektirir) |
Yapılandırma değişikliklerini işlemek için ViewModel'i kullanma
ViewModel, kullanıcı uygulamayı aktif olarak kullanırken kullanıcı arayüzüyle ilgili verileri depolamak ve yönetmek için idealdir. Kullanıcı arayüzü verilerine hızlı erişim sağlar ve döndürme, pencereyi yeniden boyutlandırma ve diğer yaygın yapılandırma değişiklikleri sırasında verilerin ağdan veya diskten yeniden getirilmesini önlemenize yardımcı olur. ViewModel'ı nasıl uygulayacağınızı öğrenmek için ViewModel rehberine bakın.
ViewModel, verileri bellekte tutar. Bu nedenle, diskteki veya ağdaki verileri almaktan daha ucuzdur. ViewModel, bir yaşam döngüsü sahibiyle (ör. gezinme hedefi veya etkinlik) ilişkilendirilir. Yapılandırma değişikliği sırasında bellekte kalır ve sistem, ViewModel'i yapılandırma değişikliğinden kaynaklanan yeni yaşam döngüsü sahibi örneğiyle otomatik olarak ilişkilendirir.
Kaydedilmiş durumun aksine, sistem tarafından başlatılan bir işlem sonlandırma sırasında ViewModel'ler yok edilir. ViewModel'de sistem tarafından başlatılan bir işlem sonlandırmasından sonra verileri yeniden yüklemek için SavedStateHandle API'yi kullanın. Alternatif olarak, veriler kullanıcı arayüzüyle ilgiliyse ve ViewModel'de tutulması gerekmiyorsa rememberSerializable kullanın. Temel veri türleri veya @Serializable kullanmak istemediğiniz senaryolar için rememberSaveable kullanın. Veriler uygulama verileriyse diske kalıcı olarak yazmak daha iyi olabilir.
Yapılandırma değişiklikleri sırasında kullanıcı arayüzü durumunuzu depolamak için zaten bir bellek içi çözümünüz varsa ViewModel'i kullanmanız gerekmeyebilir.
Sistemin başlattığı işlem sonlandırmayı işlemek için kaydedilmiş durumu yedek olarak kullanma
Compose'daki rememberSerializable ve rememberSaveable ile ViewModels'deki SavedStateHandle gibi API'ler, sistem bir bileşeni yok edip daha sonra yeniden oluşturursa kullanıcı arayüzü durumunu yeniden yüklemek için gereken verileri depolar. Karmaşık veri yapılarını daha verimli bir şekilde işlemek için SavedStateHandle, saved {} uzantısı aracılığıyla Kotlinx Serileştirme'yi destekler. Bu sayede, tür açısından güvenli nesneleri standart temel türlerle birlikte sorunsuz bir şekilde kalıcı hale getirebilir ve geri yükleyebilirsiniz. rememberSaveable kullanarak kaydedilmiş durumu nasıl uygulayacağınızı öğrenmek için State ve Jetpack Compose başlıklı makaleye bakın.
Kaydedilmiş durum paketleri, hem yapılandırma değişiklikleri hem de işlem sonlandırma sırasında kalıcı olur ancak farklı API'ler verileri serileştirdiğinden depolama ve hız açısından sınırlıdır. Serileştirilen nesneler karmaşıksa serileştirme çok fazla bellek tüketebilir. Bu işlem, yapılandırma değişikliği sırasında ana iş parçacığında gerçekleştiğinden uzun süren serileştirme, karelerin düşmesine ve görsel titremeye neden olabilir.
Kaydedilmiş durumu, bit eşlemler gibi büyük miktarda veri depolamak veya uzun süreli serileştirme ya da seri durumdan çıkarma gerektiren karmaşık veri yapıları için kullanmayın. Bunun yerine, yalnızca temel türleri ve String gibi basit, küçük nesneleri depolayın. Bu nedenle, diğer kalıcılık mekanizmaları başarısız olursa kullanıcı arayüzünü önceki durumuna geri yüklemek için gereken verileri yeniden oluşturmak üzere gerekli olan minimum miktarda veriyi (ör. kimlik) depolamak için kaydedilmiş durumu kullanın. Çoğu uygulamanın, sistem tarafından başlatılan işlem sonlandırmayı işlemek için bunu uygulaması gerekir.
Uygulamanızın kullanım alanlarına bağlı olarak, kaydedilmiş durumu hiç kullanmanız gerekmeyebilir. Örneğin, bir tarayıcı, kullanıcıyı tarayıcıdan çıkmadan önce baktığı web sayfasına geri götürebilir. Etkinliğiniz bu şekilde davranıyorsa kayıtlı durumu kullanmaktan vazgeçebilir ve bunun yerine her şeyi yerel olarak kalıcı hale getirebilirsiniz.
Ayrıca, bir etkinliği bir amaçtan açtığınızda, ekstralar paketi hem yapılandırma değiştiğinde hem de sistem etkinliği geri yüklediğinde etkinliğe teslim edilir. Bir arama sorgusu gibi bir kullanıcı arayüzü durumu verisi, etkinlik başlatıldığında amaç ekstrası olarak iletildiyse kayıtlı durum paketi yerine ekstralar paketini kullanabilirsiniz. Amaç ekstraları hakkında daha fazla bilgi edinmek için Amaç ve Amaç Filtreleri başlıklı makaleyi inceleyin.
Bu senaryoların her ikisinde de, yapılandırma değişikliği sırasında veritabanından veri yeniden yükleme döngülerini boşa harcamamak için ViewModel kullanmaya devam etmeniz gerekir.
Korunacak kullanıcı arayüzü verilerinin basit ve küçük olduğu durumlarda, durum verilerinizi korumak için yalnızca kayıtlı durum API'lerini kullanabilirsiniz.
SavedStateRegistry'yi kullanarak kayıtlı duruma bağlanma
Fragment 1.1.0 veya geçişli bağımlılığı Activity
1.0.0'dan itibaren ComponentActivity gibi kullanıcı arayüzü bileşenleri SavedStateRegistryOwner'i uygular ve bu bileşene bağlı bir SavedStateRegistry sağlar. SavedStateRegistry, bileşenlerin kaydedilmiş durumunuza bağlanarak bu durumu kullanmasına veya katkıda bulunmasına olanak tanır. Örneğin, ViewModel için Kaydedilmiş Durum modülü, SavedStateRegistry kullanarak SavedStateHandle oluşturur ve bunu ViewModel nesnelerinize sağlar. SavedStateRegistry kodunu, yaşam döngüsü sahibinizden savedStateRegistry numarasını arayarak alabilirsiniz.
Kaydedilmiş duruma katkıda bulunan bileşenler, saveState() adlı tek bir yöntemi tanımlayan SavedStateRegistry.SavedStateProvider'ı uygulamalıdır. saveState() yöntemi, bileşeninizin Bundle döndürmesine olanak tanır. Bu Bundle, bileşenden kaydedilmesi gereken tüm durumları içerir.
SavedStateRegistry, yaşam döngüsü sahibinin yaşam döngüsünün kaydetme durumu aşamasında bu yöntemi çağırır.
class SearchManager : SavedStateRegistry.SavedStateProvider {
companion object {
private const val QUERY = "query"
}
private val query: String? = null
...
override fun saveState(): Bundle {
return bundleOf(QUERY to query)
}
}
SavedStateProvider kaydetmek için SavedStateRegistry üzerinde registerSavedStateProvider() numarasını arayarak sağlayıcıyla ilişkilendirilecek bir anahtarın yanı sıra sağlayıcıyı da iletin. Sağlayıcı için daha önce kaydedilen veriler, SavedStateRegistry üzerinde consumeRestoredStateForKey() çağrılarak ve sağlayıcının verileriyle ilişkili anahtar iletilerek kaydedilmiş durumdan alınabilir.
ComponentActivity içinde, super.onCreate() numarasını aradıktan sonra onCreate() üzerinden SavedStateProvider kaydedebilirsiniz. Alternatif olarak, LifecycleOwner uygulayan bir SavedStateRegistryOwner üzerinde LifecycleObserver ayarlayabilir ve ON_CREATE etkinliği gerçekleştiğinde SavedStateProvider öğesini kaydedebilirsiniz. LifecycleObserver kullanarak daha önce kaydedilen durumun kaydedilmesini ve alınmasını SavedStateRegistryOwner'dan ayırabilirsiniz.
class SearchManager(registryOwner: SavedStateRegistryOwner) : SavedStateRegistry.SavedStateProvider {
companion object {
private const val PROVIDER = "search_manager"
private const val QUERY = "query"
}
private val query: String? = null
init {
// Register a LifecycleObserver for when the Lifecycle hits ON_CREATE
registryOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_CREATE) {
val registry = registryOwner.savedStateRegistry
// Register this object for future calls to saveState()
registry.registerSavedStateProvider(PROVIDER, this)
// Get the previously saved state and restore it
val state = registry.consumeRestoredStateForKey(PROVIDER)
// Apply the previously saved state
query = state?.getString(QUERY)
}
}
}
override fun saveState(): Bundle {
return bundleOf(QUERY to query)
}
...
}
class SearchActivity : ComponentActivity() {
private var searchManager = SearchManager(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set up your Compose UI here
setContent {
// ...
}
}
}
Karmaşık veya büyük verilerde işlem sonlandırmayı yönetmek için yerel kalıcılığı kullanma
Veritabanı veya DataStore gibi kalıcı yerel depolama alanları, uygulamanız kullanıcının cihazında yüklü olduğu sürece (kullanıcı uygulamanızın verilerini temizlemediği sürece) varlığını sürdürür. Bu tür yerel depolama alanı, sistem tarafından başlatılan uygulama işlemi sonlandırmasından etkilenmez. Ancak yerel depolama alanından belleğe okunması gerektiğinden, bu verileri almak maliyetli olabilir. Bu kalıcı yerel depolama alanı, uygulamayı açıp kapattığınızda kaybetmek istemediğiniz tüm verileri depolamak için genellikle uygulama mimarinizin bir parçasıdır.
rememberSerializable, rememberSaveable veya SavedStateHandle kullanılarak kaydedilen ViewModel ya da durum, uzun süreli depolama çözümleri değildir ve bu nedenle veritabanı gibi yerel depolama alanlarının yerine kullanılamaz. Bunun yerine, bu mekanizmaları yalnızca geçici kullanıcı arayüzü durumunu geçici olarak depolamak için kullanmalı ve diğer uygulama verileri için kalıcı depolama alanını kullanmalısınız. Uygulama modeli verilerinizi uzun süre (ör. cihaz yeniden başlatıldığında) kalıcı hale getirmek için yerel depolamadan nasıl yararlanacağınız hakkında daha fazla bilgi edinmek için Uygulama Mimarisi Kılavuzu'na göz atın.
Kullanıcı arayüzü durumunu yönetme: Böl ve fethet
Çalışmayı çeşitli kalıcılık mekanizmaları arasında bölerek kullanıcı arayüzü durumunu verimli bir şekilde kaydedip geri yükleyebilirsiniz. Çoğu durumda, bu mekanizmaların her biri, veri karmaşıklığı, erişim hızı ve kullanım ömrü arasındaki dengeye bağlı olarak uygulamada kullanılan farklı bir veri türünü saklamalıdır:
- Yerel kalıcılık: Uygulamayı açıp kapattığınızda kaybetmek istemediğiniz tüm uygulama verilerini depolar.
- Örnek: Ses dosyaları ve meta veriler içerebilen bir şarkı nesneleri koleksiyonu.
ViewModel: İlişkili kullanıcı arayüzünü görüntülemek için gereken tüm verileri, ekran kullanıcı arayüzü durumunu bellekte depolar.- Örnek: En son aramanın şarkı nesneleri ve en son arama sorgusu.
- Kayıtlı durum (
rememberSerializable,rememberSaveableveSavedStateHandle): Sistem durup kullanıcı arayüzünü yeniden oluşturursa kullanıcı arayüzü durumunu yeniden yüklemek için gereken küçük miktardaki verileri depolar. Karmaşık nesneleri burada depolamak yerine, karmaşık nesneleri yerel depolamada kalıcı hale getirin ve bu nesneler için benzersiz bir kimliği kayıtlı durum API'lerinde saklayın.- Örnek: En son arama sorgusunu saklama.
Örneğin, şarkı kitaplığınızda arama yapmanıza olanak tanıyan bir uygulamayı ele alalım. Farklı etkinliklerin nasıl ele alınması gerektiği aşağıda açıklanmıştır:
Kullanıcı bir şarkı eklediğinde ViewModel, bu verilerin yerel olarak kalıcı hale getirilmesini hemen devreder. Yeni eklenen bu şarkının kullanıcı arayüzünde gösterilmesi gerekiyorsa ViewModel nesnesindeki verileri de şarkının eklenmesini yansıtacak şekilde güncellemeniz gerekir. Tüm veritabanı ekleme işlemlerini ana iş parçacığı dışında yapmayı unutmayın.
Kullanıcı bir şarkı aradığında, veritabanından yüklediğiniz karmaşık şarkı verileri ekran kullanıcı arayüzü durumunun bir parçası olarak ViewModel nesnesinde hemen depolanmalıdır.
Uygulama arka plana geçtiğinde ve sistem durumu kaydettiğinde, işlemin yeniden oluşturulması ihtimaline karşı arama sorgusu, kayıtlı durum API'leri kullanılarak saklanmalıdır. Bilgiler, bu öğede kalıcı hale getirilen uygulama verilerini yüklemek için gerekli olduğundan, arama sorgusunu ViewModel'de SavedStateHandle saklayın veya composable'larınızda rememberSerializable ya da rememberSaveable kullanın. Verileri yüklemek ve kullanıcı arayüzünü mevcut durumuna geri getirmek için gereken tüm bilgiler burada yer alır.
Karmaşık durumları geri yükleme: parçaları yeniden birleştirme
Kullanıcının uygulamaya dönme zamanı geldiğinde kullanıcı arayüzünü yeniden oluşturmak için iki olası senaryo vardır:
- Sistem uygulama sürecini sonlandırdıktan sonra kullanıcı arayüzü yeniden oluşturulur. Sistem, kaydedilmiş durum API'lerini kullanarak sorguyu kaydetti.
ViewModel(SavedStateHandlekullanılarak) veya composable (rememberSerializableya darememberSaveablekullanılarak) sorguyu otomatik olarak geri yükler. Composable, sorguyu geri yüklerse sorguyuViewModel'ya iletir.ViewModel, önbelleğe alınmış arama sonucu olmadığını görür ve arama sonuçlarının yüklenmesini, verilen arama sorgusunu kullanarak devreder. - Yapılandırma değişikliğinden sonra kullanıcı arayüzü yeniden oluşturulur.
ViewModelörneği yok edilmediğindenViewModel, bellekteki tüm bilgileri önbelleğe alır ve veritabanına yeniden sorgu göndermesi gerekmez.
Ek kaynaklar
Kullanıcı arayüzü durumlarını kaydetme hakkında daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın.
- Kullanıcı arayüzü katmanı dokümanları
- Compose'da kullanıcı arayüzü durumunu kaydetme
- State ve Jetpack Compose belgeleri
Codelab uygulamaları
İçeriği görüntüleme
Sizin için önerilenler
- Not: JavaScript kapalıyken bağlantı metni gösterilir.
- ViewModel için Saved State modülü
- Yaşam Döngüsüne Duyarlı Bileşenlerle Yaşam Döngülerini İşleme
- ViewModel'e genel bakış