Bu kılavuzda, kullanıcı arayüzü durumu hakkında kullanıcı beklentileri ve durumu korumak için kullanılabilecek seçenekler ele alınmaktadır.
Bir etkinliğin kullanıcı arayüzü durumunun sistem tarafından etkinlikleri veya uygulamaları kaldırmasından hemen sonra kaydedilmesi ve geri yüklenmesi iyi bir kullanıcı deneyimi için esastır. Kullanıcılar, kullanıcı arayüzü durumunun aynı kalmasını bekler ancak sistem, etkinliği ve depolanmış durumunu yok edebilir.
Kullanıcı beklentileri ile sistem davranışı arasındaki boşluğu kapatmak için aşağıdaki yöntemlerin bir birleşimini kullanın:
ViewModel
nesne.- Aşağıdaki bağlamlarda örnek durumları kaydedildi:
- Jetpack Compose:
rememberSaveable
. - Görünümler:
onSaveInstanceState()
API. - ViewModels:
SavedStateHandle
.
- Jetpack Compose:
- Uygulama ve etkinlik geçişleri sırasında kullanıcı arayüzü durumunu korumak için yerel depolama.
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 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. Özellikle döndürme gibi yaygın yapılandırma değişikliklerinden sonra, verileri kullanıcı arayüzüne yüklerken gecikmeleri önleyin.
Kullanıcı beklentileri ve sistem davranışı
Yaptığı işleme bağlı olarak, kullanıcılar bu etkinlik durumunun temizlenmesini veya korunmasını bekler. Bazı durumlarda sistem, kullanıcının beklediği şeyi otomatik olarak yapar. Diğer durumlarda ise sistem, kullanıcının beklediğinin tersini yapar.
Kullanıcı tarafından başlatılan kullanıcı arayüzü durumu reddi
Kullanıcı, bir etkinlik başlattığında bu etkinliğin geçici kullanıcı arayüzü durumunun, kullanıcı etkinliği tamamen kapatana kadar aynı kalmasını bekler. Kullanıcı, aşağıdakileri yaparak bir etkinliği tamamen kapatabilir:
- Etkinliği Genel Bakış (Son Kullanılanlar) ekranından kaydırarak kaldırın.
- Ayarlar ekranından uygulamayı öldürme veya zorla çıkma.
- Cihaz yeniden başlatılıyor.
- Bir tür "tamamlama" işlemi (
Activity.finish()
ile desteklenir) tamamlamak.
Bu eksiksiz kapatma davalarında kullanıcının, etkinlikten kalıcı olarak uzaklaştığı ve etkinliği yeniden açarsa etkinliğin temiz bir durumda başlamasını beklediği varsayımında bulunur. Bu kapatma senaryolarında temel sistem davranışı, kullanıcının beklentisini karşılar. Etkinlik örneği, depolanan tüm durumlar ve etkinlikle ilişkili kaydedilmiş örnek durum kayıtlarıyla birlikte imha edilir ve bellekten kaldırılır.
Tamamen kapatma konusunda bu kuralın bazı istisnaları vardır. Örneğin bir kullanıcı, geri düğmesini kullanarak tarayıcıdan çıkmadan önce bir tarayıcının kendisini tam olarak aradığı web sayfasına götürmesini bekleyebilir.
Sistem tarafından başlatılan kullanıcı arayüzü durumu için kapatma
Kullanıcı, bir etkinliğin kullanıcı arayüzü durumunun, döndürme veya çoklu pencere moduna geçme gibi yapılandırma değişiklikleri boyunca aynı kalmasını bekler. Bununla birlikte, varsayılan olarak bu tür bir yapılandırma değişikliği gerçekleştiğinde sistem etkinliği yok eder ve etkinlik örneğinde depolanan tüm kullanıcı arayüzü durumları silinir. Cihaz yapılandırmaları hakkında daha fazla bilgi için Yapılandırma referans sayfasına bakın. Yapılandırma değişiklikleri için varsayılan davranışın geçersiz kılınabileceğini (önerilmez) unutmayın. Daha ayrıntılı bilgi için Yapılandırma değişikliğini kendiniz ele alma bölümüne bakın.
Kullanıcılar geçici olarak farklı bir uygulamaya geçip daha sonra uygulamanıza geri dönerse etkinliğinizin kullanıcı arayüzü durumunun aynı kalmasını bekler. Örneğin, kullanıcı, arama etkinliğinizde bir arama yapar ve ardından ana sayfa düğmesine basar veya bir telefon çağrısına cevap verir. Arama etkinliğine döndüğünde, arama anahtar kelimesini ve sonuçlarını önceden olduğu gibi hâlâ orada bulmayı bekler.
Bu senaryoda uygulamanız arka plana yerleştirilir. Sistem, uygulama sürecinizi bellekte tutmak için elinden geleni yapar. Ancak kullanıcı diğer uygulamalarla etkileşimde değilken sistem uygulama işlemini bozabilir. Böyle bir durumda, etkinlik örneği ve içinde depolanan tüm durumlar kaldırılır. Kullanıcı uygulamayı yeniden başlattığında etkinlik beklenmedik bir şekilde temiz bir duruma geçer. İşlem ölümü hakkında daha fazla bilgi edinmek için İşlemler ve Uygulama Yaşam Döngüsü bölümüne bakın.
Kullanıcı arayüzü durumunu koruma seçenekleri
Kullanıcının kullanıcı arayüzü durumu hakkındaki beklentileri varsayılan sistem davranışıyla eşleşmediğinde, sistem tarafından başlatılan kaldırma işleminin şeffaf olmasını sağlamak için kullanıcının kullanıcı arayüzü durumunu kaydedip geri yüklemeniz gerekir.
Kullanıcı arayüzü durumunu koruma seçeneklerinin her biri, kullanıcı deneyimini etkileyen aşağıdaki boyutlara göre değişiklik gösterir:
ViewModel | Kaydedilen örnek durumu | Kalıcı depolama | |
---|---|---|---|
Depolama alanı konumu | bellek üzerinde | bellek üzerinde | disk veya ağda |
Yapılandırma değişikliğinden sonra kurtulur | Evet | Evet | Evet |
Sistem tarafından başlatılan işlemin ölümünden sonra kurtulur | Hayır | Evet | Evet |
Kullanıcının etkinliği tamamlamasından sonra kurtarma/onFinish() | Hayır | Hayır | Evet |
Veri sınırlamaları | karmaşık nesneler kullanılabilir ancak alan, kullanılabilir bellekle sınırlıdır | String gibi basit türler ve basit, küçük nesneler için | yalnızca disk alanı veya ağ kaynağından alma maliyeti / zamanı ile sınırlıdır |
Okuma/yazma süresi | hızlı (yalnızca bellek erişimi) | yavaş (serileştirme/serileştirme 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ü ile ilgili verileri depolamak ve yönetmek için idealdir. Bu arayüz, kullanıcı arayüzü verilerine hızlı erişim sağlar. Ayrıca rotasyon, pencere yeniden boyutlandırma ve sık yapılan diğer yapılandırma değişiklikleri sırasında ağ veya diskten verilerin yeniden getirilmesini önlemenize yardımcı olur. Bir ViewModel'i nasıl uygulayacağınızı öğrenmek için ViewModel kılavuzuna bakın.
ViewModel, verileri bellekte tutar. Bu, verilerin disk veya ağdan alınmasından daha ucuz olduğu anlamına gelir. ViewModel, bir etkinlikle (veya başka bir yaşam döngüsü sahibiyle) 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 etkinlik örneğiyle otomatik olarak ilişkilendirir.
ViewModel'ler, kullanıcınız etkinliğinize veya parçanıza çekildiğinde sistem tarafından otomatik olarak yok edilir. finish()
yöntemini çağırırsanız durum, kullanıcının bu senaryolarda beklediği şekilde temizlenir.
Kaydedilen örnek durumunun aksine ViewModel'ler, sistem tarafından başlatılan bir işlem ölümü sırasında yok edilir. ViewModel'de sistem tarafından başlatılan işlem ölümünden 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 View sisteminde onSaveInstanceState()
veya Jetpack Composer'da rememberSaveable
kullanın. Veriler uygulama verileri ise bunların diskte tutulması daha iyi olabilir.
Yapılandırma değişiklikleri genelinde kullanıcı arayüzü durumunuzu depolamak için halihazırda kullandığınız bir bellek içi çözümünüz varsa ViewModel'i kullanmanız gerekmeyebilir.
Sistem tarafından başlatılan işlem ölümünü işlemek için kayıtlı örnek durumunu yedek olarak kullan
View sistemindeki onSaveInstanceState()
geri çağırması, Jetpack Compose'daki rememberSaveable
ve ViewModels'teki SavedStateHandle
, sistem söz konusu denetleyiciyi kaldırıp daha sonra yeniden oluşturursa etkinlik veya parça gibi bir kullanıcı arayüzü denetleyicisinin durumunu yeniden yüklemek için gereken verileri depolar. Kaydedilen örnek durumunun onSaveInstanceState
kullanarak nasıl uygulanacağını öğrenmek için Etkinlik Yaşam Döngüsü kılavuzunda Etkinlik durumunu kaydetme ve geri yükleme bölümüne bakın.
Kaydedilen örnek durum paketleri, hem yapılandırma değişiklikleri hem de işlem ölümü durumunda kalır ancak farklı API'ler verileri serileştirdiği için depolama ve hız ile sınırlıdır. Serileştirmedeki 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üre çalışan serileştirme, çerçevelerin düşmesine ve görsel takılmalara neden olabilir.
Kayıtlı örnek durumunu, bit eşlemler gibi büyük miktarda veriyi ve uzun süreli serileştirme ya da serileştirme gerektiren karmaşık veri yapılarını depolamak için kullanmayın. Bunun yerine, yalnızca basit türleri ve String
gibi basit, küçük nesneleri depolayın. Bu nedenle, diğer kalıcılık mekanizmalarının arızalanması durumunda kullanıcı arayüzünü önceki durumuna geri yüklemek için gereken verileri yeniden oluşturmak amacıyla gerekli minimum miktarda veriyi (ör. kimlik) depolamak için kayıtlı örnek durumunu kullanın. Çoğu uygulama, sistem tarafından başlatılan işlem ölümünü işlemek için bunu uygulamalıdır.
Uygulamanızın kullanım alanlarına bağlı olarak, kayıtlı örnek durumunu hiç kullanmanız gerekmeyebilir. Örneğin, bir tarayıcı kullanıcıyı tarayıcıdan çıkmadan önce tam olarak baktığı web sayfasına götürebilir. Etkinliğiniz bu şekilde davranıyorsa kayıtlı örnek durumunu kullanmayı bırakıp her şeyi yerel olarak devam ettirebilirsiniz.
Buna ek olarak, bir amaca ait bir etkinliği 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 iletilir. Etkinlik başlatıldığında arama sorgusu gibi bir kullanıcı arayüzü durum verisi parçası ekstra bir amaç olarak aktarıldıysa kayıtlı örnek durumu paketi yerine ekstralar paketini kullanabilirsiniz. Amaç ekstraları hakkında daha fazla bilgi edinmek için Amaç ve Amaç Filtreleri bölümüne bakın.
Her iki senaryoda da yapılandırma değişikliği sırasında veritabanından verileri yeniden yükleme döngülerinin boşa gitmesini önlemek için ViewModel
kullanmanız gerekir.
Korunacak kullanıcı arayüzü verilerinin basit ve hafif olduğu durumlarda, durum verilerinizi korumak için kayıtlı örnek durumu API'lerini yalnızca kullanabilirsiniz.
SavedStateRegistry'yi kullanarak kayıtlı duruma bağlanın
Fragment 1.1.0 veya geçişli bağımlılığı olan Activity
1.0.0'dan başlayarak, Activity
veya Fragment
gibi kullanıcı arayüzü denetleyicileri SavedStateRegistryOwner
uygular ve bu denetleyiciye bağlı bir SavedStateRegistry
sağlar. SavedStateRegistry
, bileşenlerin tüketmek veya katkıda bulunmak için kullanıcı arayüzü denetleyicinizin kayıtlı durumuna bağlanmasına olanak tanır. Örneğin, ViewModel için Kaydedilen Durum modülü bir SavedStateHandle
oluşturmak ve bunu ViewModel
nesnelerinize sağlamak için SavedStateRegistry
kullanır. getSavedStateRegistry()
yöntemini çağırarak kullanıcı arayüzü denetleyicinizden SavedStateRegistry
kodunu alabilirsiniz.
Kaydedilen duruma katkıda bulunan bileşenler, saveState()
adlı tek bir yöntemi tanımlayan SavedStateRegistry.SavedStateProvider
özelliğini uygulamalıdır. saveState()
yöntemi, bileşeninizin söz konusu bileşenden kaydedilmesi gereken herhangi bir durumu içeren bir Bundle
döndürmesine olanak tanır.
SavedStateRegistry
, bu yöntemi kullanıcı arayüzü denetleyicisinin yaşam döngüsünün kaydetme durumu aşamasında çağırır.
Kotlin
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) } }
Java
class SearchManager implements SavedStateRegistry.SavedStateProvider { private static String QUERY = "query"; private String query = null; ... @NonNull @Override public Bundle saveState() { Bundle bundle = new Bundle(); bundle.putString(QUERY, query); return bundle; } }
Bir SavedStateProvider
kaydı yapmak için SavedStateRegistry
üzerinde registerSavedStateProvider()
çağrısı ile hem sağlayıcının hem de sağlayıcının verileriyle ilişkilendirmek için bir anahtar iletin. Sağlayıcı için daha önce kaydedilmiş veriler, SavedStateRegistry
üzerinde consumeRestoredStateForKey()
çağrısı yapılarak ve sağlayıcının verileriyle ilişkili anahtarın aktarılmasıyla kayıtlı durumdan alınabilir.
Bir Activity
veya Fragment
içinde super.onCreate()
çağırdıktan sonra onCreate()
uygulamasında SavedStateProvider
kaydettirebilirsiniz. Alternatif olarak, LifecycleOwner
uygulayan bir SavedStateRegistryOwner
üzerinde LifecycleObserver
ayarlayabilir ve ON_CREATE
etkinliği gerçekleştiğinde SavedStateProvider
kaydedebilirsiniz. LifecycleObserver
kullanarak, önceden kaydedilmiş durumun kaydedilmesini ve geri alınmasını SavedStateRegistryOwner
öğesinden ayırabilirsiniz.
Kotlin
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 SearchFragment : Fragment() { private var searchManager = SearchManager(this) ... }
Java
class SearchManager implements SavedStateRegistry.SavedStateProvider { private static String PROVIDER = "search_manager"; private static String QUERY = "query"; private String query = null; public SearchManager(SavedStateRegistryOwner registryOwner) { registryOwner.getLifecycle().addObserver((LifecycleEventObserver) (source, event) -> { if (event == Lifecycle.Event.ON_CREATE) { SavedStateRegistry registry = registryOwner.getSavedStateRegistry(); // Register this object for future calls to saveState() registry.registerSavedStateProvider(PROVIDER, this); // Get the previously saved state and restore it Bundle state = registry.consumeRestoredStateForKey(PROVIDER); // Apply the previously saved state if (state != null) { query = state.getString(QUERY); } } }); } @NonNull @Override public Bundle saveState() { Bundle bundle = new Bundle(); bundle.putString(QUERY, query); return bundle; } ... } class SearchFragment extends Fragment { private SearchManager searchManager = new SearchManager(this); ... }
Karmaşık veya büyük verilerde sürecin sonlandırılmasıyla ilgili işlemleri yapmak için yerel kalıcılığı kullanın.
Veritabanı veya paylaşılan tercihler gibi kalıcı yerel depolama alanları, uygulamanız kullanıcının cihazında yüklü olduğu sürece kullanımda kalır (kullanıcı, uygulamanızın verilerini temizlemediği sürece). Bu tür yerel depolama, sistem tarafından başlatılan etkinlik ve uygulama işlemi ölümlerinde hayatta kalmaya devam etse de yerel depolama alanından belleğe okunması gerekeceğinden verilerin alınması pahalı olabilir. Bu kalıcı yerel depolama, genellikle etkinliği açıp kapattığınızda kaybetmek istemediğiniz tüm verileri depolamak için uygulama mimarinizin bir parçası olabilir.
Ne ViewModel ne de kayıtlı örnek durumu uzun vadeli depolama çözümleri değildir ve bu nedenle, veritabanı gibi yerel depolamaların yerine geçmez. Bunun yerine, bu mekanizmaları yalnızca geçici kullanıcı arayüzü durumunu geçici olarak depolamak ve diğer uygulama verileri için kalıcı depolama alanını kullanmanız gerekir. Uygulama modeli verilerinizi uzun vadede (ör. cihazı yeniden başlattığınızda) saklamak için yerel depolama alanından nasıl yararlanacağınız hakkında daha ayrıntılı bilgi için Uygulama Mimarisi Rehberi'ne bakın.
Kullanıcı arayüzü durumunu yönetme: bölme ve fethetme
İşi, çeşitli kalıcılık mekanizması türlerine bölerek kullanıcı arayüzü durumunu etkili bir şekilde kaydedip geri yükleyebilirsiniz. Çoğu durumda bu mekanizmaların her birinin; veri karmaşıklığı, erişim hızı ve kullanım ömrü avantajlarına göre etkinlikte kullanılan farklı türde verileri depolaması gerekir:
- Yerel kalıcılık: Etkinliği açıp kapattığınızda kaybetmek istemediğiniz tüm uygulama verilerini depolar.
- Örnek: Ses dosyaları ve meta verileri içerebilen şarkı nesnelerinden oluşan bir koleksiyon.
ViewModel
: İlişkili kullanıcı arayüzünü, ekran kullanıcı arayüzü durumunu görüntülemek için gereken tüm verileri belleğe depolar.- Örnek: En son aramanın ve en son arama sorgusunun şarkı nesneleri.
- Kaydedilen örnek durumu: Sistem durup kullanıcı arayüzünü yeniden oluşturursa kullanıcı arayüzü durumunu yeniden yüklemek için gereken az miktarda veriyi depolar. Karmaşık nesneleri burada depolamak yerine karmaşık nesneleri yerel depolama alanında tutun ve bu nesneler için kaydedilen örnek durumu API'lerinde benzersiz bir kimlik depolayın.
- Örnek: En son arama sorgusunu depolama.
Örneğin, şarkı kitaplığınızda arama yapmanızı sağlayan bir etkinlik düşünün. Farklı etkinliklerin nasıl ele alınacağı aşağıda açıklanmıştır:
Kullanıcı bir şarkı eklediğinde ViewModel
, bu verilerin yerel olarak kalması için yetkiyi hemen verir. Yeni eklenen bu şarkının kullanıcı arayüzünde gösterilmesi gerekiyorsa şarkı ekleneni yansıtmak için ViewModel
nesnesindeki verileri de güncellemeniz gerekir. Tüm veritabanı ekleme işlemlerini ana iş parçacığından yapmayı unutmayın.
Kullanıcı bir şarkı aradığında, veritabanından yüklediğiniz karmaşık şarkı verileri ne olursa olsun ekran kullanıcı arayüzü durumu kapsamında hemen ViewModel
nesnesinde depolanmalıdır.
Etkinlik arka plana gittiğinde ve sistem, kayıtlı örnek durumu API'lerini çağırdığında, işlemin yeniden oluşturulması ihtimaline karşı arama sorgusu kayıtlı örnek durumunda depolanmalıdır. Buradaki uygulama verilerini yüklemek için gerekli olan bilgiler gerektiğinden, arama sorgusunu ViewModel SavedStateHandle
içinde depolayın. Verileri yüklemek ve kullanıcı arayüzünü
mevcut durumuna geri getirmek için ihtiyacınız olan tüm bilgiler bunlardır.
Karmaşık durumları geri yükleme: parçaları yeniden birleştirme
Kullanıcının etkinliğe dönme zamanı geldiğinde, etkinliği yeniden oluşturmak için iki olası senaryo vardır:
- Etkinlik, sistem tarafından durdurulduktan sonra yeniden oluşturulur. Sistem, sorguyu kayıtlı bir örnek durum paketine kaydeder ve
SavedStateHandle
kullanılmazsa kullanıcı arayüzü, sorguyuViewModel
öğesine iletmelidir.ViewModel
, önbelleğe alınan arama sonucunun olmadığını görür ve belirtilen arama sorgusunu kullanarak arama sonuçlarını yükleme yetkisi verir. - Etkinlik, bir yapılandırma değişikliğinden sonra oluşturulur.
ViewModel
örneği yok edilmediği içinViewModel
tüm bilgileri bellekte önbelleğe alır ve veritabanını yeniden sorgulamasına gerek yoktur.
Ek kaynaklar
Kullanıcı arayüzü durumlarını kaydetme hakkında daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın.
Bloglar
- ViewModels: Basit bir örnek
- ViewModels: Kalıcılık,
onSaveInstanceState()
, Kullanıcı Arayüzü Durumunu ve Yükleyicileri Geri Yükleme - Android yaşam döngüsüne duyarlı bileşenler codelab'i
Sizin için önerilenler
- Not: Bağlantı metni JavaScript kapalıyken görüntülenir
- ViewModel için Kayıtlı Durum modülü
- Yaşam Döngüsüne Duyarlı Bileşenlerle Yaşam Döngülerini Yönetme
- ViewModel'e genel bakış