Merhabalar,

Bu seride doküman okuma alışkanlığımı geliştirmek ve Android temellerine dair daha kapsamlı bilgi edinmek adına developer.android.com üzerinden seçtiğim konular hakkında notlarımı paylaşıyor olacağım. Keyifli okumalar:)

Activity state ve bellekten çıkarma

Sistem, RAM’i boşaltması gerektiğinde işlemleri öldürür; sistemin belirli bir süreci öldürme olasılığı, sürecin o andaki durumuna bağlıdır. Süreç durumu, sırayla, süreçte çalışan aktivitenin durumuna bağlıdır. Aşağıdaki tablo aktivite durumu ve sistemin süreci öldürme olasılığı arasındaki ilişkiyi göstermektedir.

Sistem, belleği boşaltmak için hiçbir aktiviteyi doğrudan öldürmez. Bunun yerine, aktivitenin yürütüldüğü süreci öldürür, yalnızca onu değil, süreçte çalışan diğer her şeyi de yok eder. Bir kullanıcı, ilgili uygulamayı öldürmek için Ayarlar altındaki Uygulama Yöneticisini kullanarak da bir işlemi sonlandırabilir.

Geçici UI state’i kaydetme ve geri yükleme

Bir kullanıcı, bir aktivitenin UI durumunun, rotate etme veya çoklu pencere moduna geçme gibi bir yapılandırma değişikliği boyunca aynı kalmasını bekler. Ancak, böyle bir yapılandırma değişikliği meydana geldiğinde sistem default olarak aktiviteyi yok eder ve aktivite örneğinde depolanan tüm UI state’i siler. Benzer şekilde, bir kullanıcı, geçici olarak uygulamamızdan farklı bir uygulamaya geçip daha sonra uygulamamıza geri dönerse, UI state’in aynı kalmasını bekler. Ancak sistem, kullanıcı uzaktayken ve aktivite durdurulduğunda uygulamamızın sürecini bozabilir.

Aktivite, sistem kısıtlamaları nedeniyle yok edildiğinde, ViewModel, onSaveInstanceState() ve/veya yerel depolamanın bir kombinasyonunu kullanarak kullanıcının geçici UI state’ini korumamız gerekir.

UI verilerimiz, basit bir veri türü ise, hem yapılandırma değişikliklerinde hem de sistemin bellek açmak için aktivitemizi öldürdüğünde UI durumunu sürdürmek için tek başına onSaveInstanceState() öğesini kullanabiliriz. Yine de çoğu durumda hem ViewModel hem de onSaveInstanceState()’i doğru yerlerde kombine şekilde kullanmamız gerekir.

Kullanıcımızın Geri düğmesine basması veya aktivitenin finish() yöntemini çağırarak kendi imhasını bildirmesi nedeniyle aktivitenin yok edildiği birkaç senaryo vardır. Kullanıcı Geri’ye bastığı veya kendi kendine bittiği için aktivite yok edildiğinde, hem sistemin hem de kullanıcının bu Acitivity örneği kavramı ortadan kalkar. Bu senaryolarda kullanıcının beklentisi sistemin davranışı ile eşleşir ve bizim ekstra bir işimiz olmaz.

Ancak sistem, sistem kısıtlamaları (konfigürasyon değişikliği veya bellek baskısı gibi) nedeniyle aktiviteyi yok ederse, o zaman gerçek Activity örneği gitmiş olsa da, sistem onun var olduğunu hatırlar. Kullanıcı aktiviteye geri dönmeye çalışırsa sistem, aktivite yok edildiği andaki durumunu açıklayan kaydedilmiş verileri kullanarak bu aktivitenin yeni bir örneğini oluşturur.

Sistemin önceki durumu geri yüklemek için kullandığı kayıtlı verilere instance state denir ve bir Bundle nesnesinde depolanan key/value çiftlerininden oluşur. Default olarak sistem, aktivite düzenimizdeki her bir View nesnesi hakkındaki bilgileri (bir EditText‘e girilen metin değeri gibi) kaydetmek için Bundle instance state’i kullanır. Bu nedenle, aktivite örneği yok edilir ve yeniden oluşturulursa, layout durumu, bizim tarafımızdan herhangi bir kod eklenmesi gerekmeden önceki durumuna geri yüklenir.

Not: Android sisteminin etkinliğimizdeki görünümlerin durumunu geri yüklemesi için, her view’in android:id‘si olmalıdır.

Bir Bundle nesnesi, main thread’de serileştirme gerektirdiğinden ve sistem işlem belleğini tükettiğinden, sadece küçük değerler saklanmalıdır. Bir (key value) veriyi saklamak dışında kalıcı yerel depolamayı, onSaveInstanceState() yöntemini ve ViewModel sınıfını kullanarak verileri korumaya yönelik bütünsel bir yaklaşım izlememiz önerilir.

onSaveInstanceState() kullanarak UI state’i kaydetme

Aktivitemiz durmaya başladığında sistem onSaveInstanceState() yöntemini çağırır, böylece aktivite durum bilgilerini bir örnek durum paketine kaydedebilir. Bu yöntemin varsayılan uygulaması, bir EditText ‘deki metin veya bir ListView’deki kaydırma konumu gibi, etkinliğin görünüm hiyerarşisinin durumu hakkında geçici bilgileri kaydeder.

Aktivitemizin ek örnek durumu bilgilerini kaydetmek için onSaveInstanceState() öğesini override etmemiz ve aktivitemizin beklenmedik bir şekilde yok edilmesi durumunda kaydedilen Bundle nesnesine key/value çiftleri eklememiz gerekir. onSaveInstanceState() öğesini override ederek, varsayılan uygulamanın görünüm hiyerarşisinin durumunu kaydetmesini istiyorsak superclassı implement etmeliyiz. Örneğin:

Not: onSaveInstanceState(), kullanıcı aktiviteyi açıkça kapattığında veya diğer durumlarda finish() çağrıldığında çağrılmaz.

Kaydedilmiş Instance state’i kullanarak aktivite UI state’ini restore etme

Aktivitemiz daha önce yok edildikten sonra yeniden oluşturulduğunda, kayıtlı instance state’i, sistemin aktivitemize aktardığı Bundle’dan çekebiliriz. Hem onCreate() hem de onRestoreInstanceState() callbackleri, instance state bilgilerini içeren aynı Bundle’ı alır.

OnCreate() yöntemi, sistem aktivitenin yeni bir örneğini mi yoksa önceki bir örneğini mi yeniden oluşturuyor bilmediğimizden, buradan bilgileri çekmeye çalışmadan önce Bundle durumunun boş olup olmadığını kontrol etmemiz gerekir. Null ise, sistem, yok edilen bir öncekini geri yüklemek yerine aktivitenin yeni bir örneğini oluşturuyor demektir.

Örneğin, aşağıdaki kod parçacığı, bazı durum verilerini onCreate() içinde nasıl geri yükleyebileceğimizi gösterir:

onCreate() sırasında durumu geri almak yerine, sistemin onStart() yönteminden sonra çağırdığı onRestoreInstanceState() öğesini kullanabiliriz. Sistem, yalnızca geri yüklenecek kaydedilmiş bir durum varsa onRestoreInstanceState() öğesini çağırır, bu nedenle Bundle’ın null olup olmadığını kontrol etmemiz gerekmez:

Aktiviteler arasında gezinme

Bir uygulamanın, uygulama ömrü boyunca belki de birçok kez bir etkinliğe girip çıkması muhtemeldir. Örneğin, kullanıcı cihazın Geri düğmesine dokunabilir veya aktivitenin farklı bir aktivite başlatması gerekebilir.

Bir activity’den bir diğerini başlatmak

Bir aktivitenin genellikle bir noktada başka bir aktiviteye başlaması gerekir. Bu ihtiyaç, örneğin bir uygulamanın mevcut ekrandan yenisine geçmesi gerektiğinde ortaya çıkar.

Aktivitemizin başlamak üzere olduğu yeni aktiviteden bir sonuç isteyip istemediğine bağlı olarak, yeni aktiviteyi startActivity() veya startActivityForResult() yöntemini kullanarak başlatabiliriz. Her iki durumda da bir Intent nesnesi iletiriz.

Intent nesnesi, tam olarak başlatmak istediğimiz etkinliği belirtir veya gerçekleştirmek istediğimiz eylemin türünü tanımlar . Bir Intent nesnesi, başlatılan aktivite tarafından kullanılacak küçük miktarlarda veri de taşıyabilir.

Yeni başlatılan aktivitenin bir sonuç döndürmesi gerekmiyorsa, mevcut aktivite startActivity() yöntemini çağırarak başlatabilir.

Kendi uygulamamızda çalışırken, genellikle bilinen bir aktiviteyi başlatmamız yeterlidir;

Uygulamamız, aktivitemizden elde edilen verileri kullanarak e-posta, kısa mesaj veya durum güncellemesi göndermek gibi bazı eylemler gerçekleştirmek isteyebilir. Bu durumda, uygulamamızın bu tür eylemleri gerçekleştirecek kendi aktiviteleri olmayabilir, bu nedenle, eylemleri bizim için gerçekleştirebilecek olan cihazdaki diğer uygulamalar tarafından sağlanan aktivitelerden yararlanabiliriz. Buradan Intent’ler önemlidir. Gerçekleştirmek istediğimiz bir eylemi tanımlayan bir intent oluşturabiliriz ve sistem uygun aktiviteyi başka bir uygulamadan başlatır. Intent’i işleyebilecek birden fazla aktivite varsa, kullanıcı hangisini kullanacağını seçebilir. Örneğin, kullanıcının bir e-posta mesajı göndermesine izin vermek için;

Bazen bir aktivite bittiğinde ondan bir sonuç almak isteriz. Örneğin, kullanıcının bir kişi listesinden bir kişiyi seçmesini sağlayan bir aktivite başlatabiliriz; bitince seçilen kişiyi döndürür. Bunu yapmak için, startActivityForResult(Intent, int) yöntemini kullabiliriz. Bu tanımlayıcı, aynı aktiviteden startActivityForResult(Intent, int) öğesine yapılan birden çok çağrı arasındaki belirsizliği ortadan kaldırmak içindir. Genel tanımlayıcı değildir ve diğer uygulamalar veya etkinliklerle çakışma riski taşımaz. Sonuç, onActivityResult(int, int, Intent) yöntemi aracılığıyla geri gelir.

Bir child aktivite çıktığında, verileri ebeveynine döndürmek için setResult(int) öğesini çağırabilir. Child aktivite her zaman bir sonuç kodu sağlamalıdır; bu, RESULT_CANCELED, RESULT_OK standart sonuçları veya RESULT_FIRST_USER ile başlayan herhangi bir özel değer olabilir. Ayrıca, child aktivite isteğe bağlı olarak, istediği herhangi bir ek veriyi içeren bir Intent nesnesi döndürebilir. Ebeveyn aktivite , bilgileri almak için onActivityResult(int, int, Intent) yöntemini ve ana etkinliğin orijinal olarak sağladığı tamsayı tanımlayıcısını kullanır.

Eğer bir child aktivite çökme gibi herhangi bir nedenle başarısız olursa, üst etkinlik, RESULT_CANCELED koduyla bir sonuç alır.

Aktivitiler arası koordinasyon

Bir aktiviteden diğerini başlattığımızda, her ikisi de yaşam döngüsü geçişleri yaşar. İlk aktivite çalışmayı durdurur ve diğer aktivite oluşturulurken Paused veya Stopped durumuna girer. Bu aktivitelerin diske veya başka bir yere kaydedilmiş verileri paylaşması durumunda, ilk aktivitenin ikincisi oluşturulmadan önce tamamen durdurulmadığını anlamak önemlidir. Aksine, ikincisini başlatma süreci, birinciyi durdurma süreciyle örtüşür.

Aktivite A, Aktivite B’yi başlattığında gerçekleşen işlemlerin sırası şöyledir:

· Aktivite A’nın onPause() yöntemi yürütülür.

· Aktivite B’nin onCreate(), onStart() ve onResume() yöntemleri sırayla yürütülür. (B Etkinliği artık kullanıcı odaklıdır.)

· Ardından, Activity A ekranda artık görünmüyorsa, onStop() yöntemi yürütülür.

Bu öngörülebilir lifecycle callback serisi, bilgilerin bir etkinlikten diğerine geçişini yönetmemize olanak tanır.

Serinin devamı için;

Okuduğunuz için teşekkür ederim, bir sonraki yazıda görüşmek üzere :)

Referanslar ;
https://developer.android.com/guide/components/activities/activity-lifecycle

--

--