Kullanıcı arayüzü durumlarını kaydet

Bu kılavuzda, kullanıcı arayüzü durumu ile ilgili kullanıcı beklentileri ve durumu korumak için kullanılabilecek seçenekler açıklanmaktadır.

Bir etkinliğin kullanıcı arayüzü durumunun sistem, etkinlikleri veya uygulamaları kaldırmasından hemen sonra 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, 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öntemleri bir arada kullanın:

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 bulmaya 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, kullanıcı arayüzüne veri yüklerken gecikmelerden kaçının.

Kullanıcı beklentileri ve sistem davranışı

Kullanıcılar, gerçekleştirdiği işleme bağlı olarak, bu etkinlik durumunun temizlenmesini veya durumunun korunmasını bekler. Bazı durumlarda sistem, kullanıcının beklediğini otomatik olarak yapar. Diğer durumlarda sistem, kullanıcının beklediğinin tersini yapar.

Kullanıcı tarafından başlatılan kullanıcı arayüzü durumu kapatma

Kullanıcı, bir etkinlik başlattığında etkinliği tamamen kapatana kadar bu etkinliğin geçici kullanıcı arayüzü durumunun 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ı sonlandırmak veya zorla kapatmak.
  • Cihaz yeniden başlatılıyor.
  • Bir tür "tamamlama" işlemi tamamlamak (bu işlem Activity.finish() ile desteklenir).

Bu tür ret davalarında kullanıcının, aktiviteden kalıcı olarak ayrıldığı ve etkinliği yeniden açarsa etkinliğin temiz bir durumda başlamasını beklediği varsayılır. Bu kapatma senaryolarında temel sistem davranışı, kullanıcının beklentisini karşılar. Etkinlik örneği, içinde saklanan durumlarla ve etkinlikle ilişkili tüm kaydedilmiş örnek durum kayıtlarıyla birlikte imha edilir ve bellekten kaldırılır.

Tamamen kapatmayla ilgili bu kuralın bazı istisnaları vardır. Örneğin, bir kullanıcı bir tarayıcının geri düğmesini kullanarak tarayıcıdan çıkmadan önce tam olarak baktığı web sayfasına götürmesini bekleyebilir.

Sistem tarafından başlatılan kullanıcı arayüzü durumunu 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 kullanıcı arayüzü durumları silinir. Cihaz yapılandırmaları hakkında daha fazla bilgi edinmek için Yapılandırma referans sayfasına bakın. Yapılandırma değişiklikleri için varsayılan davranışı geçersiz kılmanın mümkün olsa da, önerilmediğini unutmayın. Daha ayrıntılı bilgi için Yapılandırma değişikliğini kendiniz 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üğünde de 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ını cevaplar. Arama etkinliğine döndüğünde, arama anahtar kelimesini ve sonuçlarını tam olarak eskisi gibi bulmayı bekler.

Bu senaryoda uygulamanız arka plana yerleştirilir. Sistem, uygulama sürecinizi bellekte tutmak için elinden geleni yapar. Ancak sistem, kullanıcı diğer uygulamalarla etkileşimde değilken uygulama işlemini bozabilir. Bu durumda, etkinlik örneği ve içinde depolanan tüm durumlar imha edilir. Kullanıcı uygulamayı yeniden başlattığında etkinlik beklenmedik bir şekilde temiz bir durumda olur. İşlem ölümü hakkında daha fazla bilgi edinmek için Süreçler 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ü durumuyla ilgili beklentileri varsayılan sistem davranışıyla eşleşmediğinde, sistem tarafından başlatılan imha işleminin kullanıcı için şeffaf olduğundan emin olmak için kullanıcının kullanıcı arayüzü durumunu kaydedip geri yüklemeniz gerekir.

Kullanıcı arayüzü durumunu koruma seçenekleri, kullanıcı deneyimini etkileyen aşağıdaki boyutlara göre değişir:

ViewModel Kayıtlı örnek durumu Kalıcı depolama alanı
Depolama alanı konumu bellek üzerinde bellek üzerinde diskte veya ağda
Yapılandırma değişikliğinden sonra kurtulur Evet Evet Evet
Sistem tarafından başlatılan işlemin devre dışı bırakılmasından kurtulur Hayır Evet Evet
Kullanıcının etkinlik kapatma işlemini tamamlamasından sonra geçer/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 yalnızca temel türler ve String gibi 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 işlemi 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 işlem, kullanıcı arayüzü verilerine hızlı erişim sağlar ve 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. 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 otomatik olarak yapılandırma değişikliğinden kaynaklanan yeni etkinlik örneğiyle ilişkilendirir.

ViewModel'ler, kullanıcınız etkinliğinizden veya parçanızdan ç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 sonlandırma 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 JetpackCompose'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 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 bu denetleyiciyi kaldırıp yeniden oluşturursa etkinlik veya parça gibi bir kullanıcı arayüzü denetleyicisinin durumunu yeniden yüklemek için gereken verileri depolar. onSaveInstanceState kullanarak kayıtlı örnek durumunu nasıl uygulayacağınızı öğrenmek için Etkinlik Yaşam Döngüsü kılavuzundaki Etkinlik durumunu kaydetme ve geri yükleme bölümüne bakın.

Kayıtlı örnek durumu paketleri, hem yapılandırma değişiklikleri hem de işlem ölümü boyunca korunur ancak farklı API'ler verileri seri hale getirdiği için depolama alanı ve hız ile sınırlıdır. Seri hale getirilen 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.

Bit eşlemler veya uzun serileştirme ya da serileştirme gerektiren karmaşık veri yapıları gibi büyük miktarda veriyi depolamak için kayıtlı örnek durumunu kullanmayın. Bunun yerine, yalnızca temel türleri ve String gibi basit, küçük nesneleri depolayın. Bu nedenle, kayıtlı örnek durumunu kullanarak diğer kalıcılık mekanizmalarının başarısız olması durumunda kullanıcı arayüzünü önceki durumuna geri yüklemek için gereken verileri yeniden oluşturmak amacıyla kimlik gibi minimum miktarda veriyi depolayı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 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ı ö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 ekstra bir intent olarak aktarıldıysa kayıtlı örnek durumu paketi yerine ekstralar paketini kullanabilirsiniz. Amaç ekstraları hakkında daha fazla bilgi için Amaç ve Amaç Filtreleri bölümünü inceleyin.

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 harcanmasını ö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 tek başına kullanabilirsiniz.

Kaydedilen Durum Kaydını kullanarak kayıtlı duruma bağlanma

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 buna katkıda bulunmak için kullanıcı arayüzü denetleyicinizin kayıtlı durumuna bağlanmasına olanak tanır. Örneğin, ViewModel için Kayıtlı Durum modülü, bir SavedStateHandle oluşturmak ve bunu ViewModel nesnelerinize sağlamak için SavedStateRegistry kullanır. SavedStateRegistry bilgisini, getSavedStateRegistry() yöntemini çağırarak kullanıcı arayüzü denetleyicinizden 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 tüm durumları içeren bir Bundle döndürmesini sağlar. 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 kaydettirmek için SavedStateRegistry üzerinde registerSavedStateProvider() numarasını arayarak hem sağlayıcının hem de sağlayıcının verileriyle ilişkilendirmek üzere bir anahtar iletin. Sağlayıcı için önceden 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.

Activity veya Fragment içinde, super.onCreate() çağırdıktan sonra onCreate() hizmetine SavedStateProvider kaydettirebilirsiniz. Alternatif olarak, LifecycleOwner uygulayan bir SavedStateRegistryOwner üzerinde LifecycleObserver ayarlayabilir veON_CREATE etkinliği gerçekleştiğinde SavedStateProvider özelliğini kaydedebilirsiniz. LifecycleObserver kullanarak, önceden kaydedilen durumun kaydedilip alınmasını SavedStateRegistryOwner kendisinden 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 işlem sonlandırmayı işlemek 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 varlığını sürdürür (kullanıcı, uygulamanızın verilerini temizlemediği sürece). Bu tür yerel depolama alanları, sistem tarafından başlatılan etkinlik ve uygulama işleminin ölümünden sonra varlığını sürdürürken, yerel depolama alanından belleğe okunması gerekeceğinden bu depolama alanının 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.

ViewModel ve kaydedilmiş ö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 için kullanmalısınız. Kalıcı depolamayı ise diğer uygulama verileri için kullanmalısınız. Uygulama modeli verilerinizi uzun vadede (ör. cihaz yeniden başlatıldığında) saklamak için yerel depolama alanından nasıl yararlanacağınız hakkında daha fazla bilgiyi Uygulama Mimarisi Rehberi'nde bulabilirsiniz.

Kullanıcı arayüzü durumunu yönetme: bölme ve fethetme

Çalışmaları çeşitli kalıcılık mekanizması türlerine bölerek kullanıcı arayüzü durumunu etkili bir şekilde kaydedebilir ve geri yükleyebilirsiniz. Çoğu durumda bu mekanizmaların her biri; veri karmaşıklığı, erişim hızı ve ömrün dengelerine bağlı olarak etkinlikte kullanılan farklı türde verileri depolamalıdır:

  • Yerel kalıcılık: Etkinliği açıp kapatırsanız kaybetmek istemediğiniz tüm uygulama verilerini depolar.
    • Örnek: Ses dosyaları ve meta verileri içerebilecek şarkı nesnelerinden oluşan bir koleksiyon.
  • ViewModel: İlişkili kullanıcı arayüzünü (ekran kullanıcı arayüzü durumu) görüntülemek için gereken tüm verileri bellekte depolar.
    • Örnek: En son aramanın ve en son arama sorgusunun şarkı nesneleri.
  • Kayıtlı ö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 yerel depolama alanındaki karmaşık nesneleri tutun ve kaydedilen örnek durumu API'lerinde bu nesnelere ait 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 saklanması için yetki verir. Yeni eklenen bu şarkının kullanıcı arayüzünde gösterilmesi gerekiyorsa şarkı ekleme işlemini yansıtmak için ViewModel nesnesindeki verileri de güncellemeniz gerekir. Ana iş parçacığındaki tüm veritabanı eklemelerini yapmayı unutmayın.

Kullanıcı bir şarkı aradığında, veritabanından yüklediğiniz karmaşık şarkı verileri ne olursa olsun hemen ekran kullanıcı arayüzü durumunun bir parçası olarak ViewModel nesnesinde depolanmalıdır.

Etkinlik arka plana gittiğinde ve sistem, kayıtlı örnek durumu API'lerini çağırdığında arama sorgusu, işlemin yeniden oluşturulması ihtimaline karşı kayıtlı örnek durumunda depolanmalıdır. Bu bilgiler devam eden uygulama verilerini yüklemek için gerekli olduğundan 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 geri 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, kayıtlı bir örnek durumu paketine kaydedilmiş sorguya sahiptir ve SavedStateHandle kullanılmazsa kullanıcı arayüzü sorguyu ViewModel öğesine iletir. ViewModel, hiçbir arama sonucunun önbelleğe alınmadığını görür ve belirtilen arama sorgusunu kullanarak arama sonuçlarını yükleme yetkisi verir.
  • Etkinlik, yapılandırma değişikliğinden sonra oluşturulur. ViewModel örneği silinmediğinden, ViewModel 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