Android Kotlin Hakkında Temel Bilgiler 04.2: Karmaşık yaşam döngüsü durumları

Bu codelab, Android Kotlin Hakkında Temel Bilgiler kursunun bir parçasıdır. Bu kurstan en iyi şekilde yararlanmak için codelab'leri sırayla tamamlamanızı öneririz. Kursla ilgili tüm codelab'ler Android Kotlin Hakkında Temel Bilgiler codelab'leri açılış sayfasında listelenir.

Giriş

Son codelab'de Activity ve Fragment yaşam döngüleri hakkında bilgi edinmiş ve yaşam döngüsü durumu etkinliklerde ve parçalarda değiştiğinde çağrılan yöntemleri incelemiştiniz. Bu codelab'de etkinlik yaşam döngüsünü daha ayrıntılı bir şekilde inceliyorsunuz. Ayrıca, daha iyi düzenlenmiş ve bakımı daha kolay kodlarla yaşam döngüsü etkinliklerini yönetmenize yardımcı olabilecek Android Jetpack'in yaşam döngüsü kitaplığı hakkında da bilgi edineceksiniz.

Bilmeniz gerekenler

  • Etkinlik nedir ve uygulamanızda nasıl etkinlik oluşturabilirsiniz?
  • Activity ve Fragment yaşam döngülerinin temelleri ve bir etkinlik durumlar arasında hareket ettiğinde çağrılan geri çağırmalar.
  • Etkinlik veya parça yaşam döngüsünde farklı zamanlarda işlemler gerçekleştirmek için onCreate() ve onStop() yaşam döngüsü geri çağırma yöntemlerini nasıl geçersiz kılacağınız.

Neler öğreneceksiniz?

  • Yaşam döngüsü geri çağırma yöntemlerinde uygulamanızın bölümlerini nasıl ayarlayacağınız, başlatacağınız ve durduracağınız.
  • Yaşam döngüsü gözlemcisi oluşturmak ve etkinlik ile parça yaşam döngüsünü daha kolay yönetmek için Android yaşam döngüsü kitaplığının nasıl kullanılacağı.
  • Android'in işlem kapatma işlemlerinin uygulamanızdaki verileri nasıl etkilediği ve Android uygulamanızı kapattığında bu verileri otomatik olarak nasıl kaydedip geri yükleyebileceğiniz.
  • Cihaz döndürme ve diğer yapılandırma değişikliklerinin yaşam döngüsü durumlarında nasıl değişiklikler oluşturduğu ve uygulamanızın durumunu nasıl etkilediği.

Yapacaklarınız

  • DessertClicker uygulamasını zamanlayıcı işlevi içerecek şekilde değiştirin ve bu zamanlayıcıyı etkinlik yaşam döngüsünün çeşitli zamanlarında başlatıp durdurun.
  • Uygulamayı Android yaşam döngüsü kitaplığını kullanacak şekilde değiştirin ve DessertTimer sınıfını yaşam döngüsü gözlemcisine dönüştürün.
  • Uygulamanızın işlem kapatma sürecini ve bu süreçte gerçekleşen yaşam döngüsü geri çağırmalarını simüle etmek için Android Debug Bridge'i (adb) kurup kullanın.
  • Uygulama beklenmedik şekilde kapatılırsa kaybolabilecek uygulama verilerini saklamak için onSaveInstanceState() yöntemini uygulayın. Uygulama tekrar başladığında bu verileri geri yüklemek için kod ekleyin.

Bu codelab'de, önceki codelab'deki DessertClicker uygulamasını genişleteceksiniz. Arka plan zamanlayıcı ekleyip uygulamayı Android yaşam döngüsü kitaplığını kullanacak şekilde dönüştürürsünüz.

Önceki codelab'de, çeşitli yaşam döngüsü geri çağırmalarını geçersiz kılarak ve sistem bu geri çağırmaları çağırdığında günlük kaydı oluşturarak etkinlik ve parça yaşam döngülerini nasıl gözlemleyeceğinizi öğrendiniz. Bu görevde, DessertClicker uygulamasında yaşam döngüsü görevlerini yönetmeyle ilgili daha karmaşık bir örneği inceleyeceksiniz. Çalışma süresinin saniye sayısını içeren bir günlük ifadesini her saniyede bir yazdıran bir zamanlayıcı kullanacaksınız.

1. adım: DessertTimer'ı ayarlayın

  1. Son codelab'deki DessertClicker uygulamasını açın. (Uygulamanız yoksa DessertClickerLogs'u buradan indirebilirsiniz.)
  2. Proje görünümünde, java > com.example.android.dessertclicker'ı genişletin ve DessertTimer.kt'ı açın. Şu anda kodun tamamının yorum satırı olarak işaretlendiğini, dolayısıyla uygulamanın bir parçası olarak çalışmadığını unutmayın.
  3. Düzenleyici penceresindeki tüm kodu seçin. Code > Comment with Line Comment'ı (Kod > Satır Yorumuyla Yorum Yap) seçin veya Control+/ tuşuna (Mac'te Command+/) basın. Bu komut, dosyadaki tüm kodların yorum satırı olmaktan çıkarılmasını sağlar. (Android Studio, uygulamayı yeniden oluşturana kadar çözümlenmemiş referans hataları gösterebilir.)
  4. DessertTimer sınıfının, zamanlayıcıyı başlatan ve durduran startTimer() ve stopTimer() sınıflarını içerdiğini unutmayın. startTimer() çalışırken zamanlayıcı, her saniyede bir günlük mesajı yazdırır. Bu mesajda, zamanlayıcının çalıştığı toplam süre de yer alır. stopTimer() yöntemi ise zamanlayıcıyı ve günlük ifadelerini durdurur.
  1. MainActivity.kt adlı kişiyi aç. Sınıfın üst kısmında, dessertsSold değişkeninin hemen altına zamanlayıcı için bir değişken ekleyin:
private lateinit var dessertTimer : DessertTimer;
  1. onCreate() bölümüne gidin ve setOnClickListener() çağrısından hemen sonra yeni bir DessertTimer nesnesi oluşturun:
dessertTimer = DessertTimer()


Artık bir tatlı zamanlayıcı nesneniz olduğuna göre, zamanlayıcının yalnızca etkinlik ekrandayken çalışması için zamanlayıcıyı nerede başlatıp durdurmanız gerektiğini düşünün. Sonraki adımlarda birkaç seçeneği inceleyebilirsiniz.

2. adım: Zamanlayıcıyı başlatın ve durdurun

onStart() yöntemi, etkinlik görünür hale gelmeden hemen önce çağrılır. onStop() yöntemi, etkinlik görünür olmaktan çıktıktan sonra çağrılır. Bu geri çağırmalar, zamanlayıcıyı başlatmak ve durdurmak için iyi birer aday gibi görünüyor.

  1. MainActivity sınıfında, onStart() geri çağırma işlevinde zamanlayıcıyı başlatın:
override fun onStart() {
   super.onStart()
   dessertTimer.startTimer()

   Timber.i("onStart called")
}
  1. Zamanlayıcıyı onStop() içinde durdurma:
override fun onStop() {
   super.onStop()
   dessertTimer.stopTimer()

   Timber.i("onStop Called")
}
  1. Uygulamayı derleyip çalıştırın. Android Studio'da Logcat bölmesini tıklayın. Logcat arama kutusuna dessertclicker girin. Bu, hem MainActivity hem de DessertTimer sınıflarına göre filtreleme yapar. Uygulama başladığında zamanlayıcının da hemen çalışmaya başladığını unutmayın.
  2. Geri düğmesini tıkladığınızda zamanlayıcının tekrar durduğunu görürsünüz. Hem etkinlik hem de kontrol ettiği zamanlayıcı yok edildiği için zamanlayıcı durur.
  3. Uygulamaya dönmek için son kullanılanlar ekranını kullanın. Logcat'te zamanlayıcının 0'dan yeniden başladığını fark edin.
  4. Paylaş düğmesini tıklayın. Logcat'te zamanlayıcının çalışmaya devam ettiğini fark edin.

  5. Ana Sayfa düğmesini tıklayın. Logcat'te zamanlayıcının çalışmayı durdurduğunu fark edin.
  6. Uygulamaya dönmek için son kullanılanlar ekranını kullanın. Logcat'te zamanlayıcının kaldığı yerden tekrar başladığını fark edin.
  7. MainActivity içinde, onStop() yönteminde stopTimer() çağrısını yorum satırı yapın. stopTimer() ifadesini yorum satırı olarak işaretlemek, onStart() içinde bir işlem başlattığınız ancak onStop() içinde tekrar durdurmayı unuttuğunuz durumu gösterir.
  8. Uygulamayı derleyip çalıştırın ve zamanlayıcı başladıktan sonra Ana Sayfa düğmesini tıklayın. Uygulama arka planda olsa bile zamanlayıcı çalışmaya devam eder ve sistem kaynaklarını sürekli olarak kullanır. Zamanlayıcının çalışmaya devam etmesi uygulamanız için bellek sızıntısıdır ve muhtemelen istediğiniz davranış değildir.

    Genel olarak, bir geri çağırma işlevinde bir şeyi ayarladığınızda veya başlattığınızda, ilgili geri çağırma işlevinde bu şeyi durdurur veya kaldırırsınız. Böylece, artık gerekmediğinde hiçbir şeyin çalışmasını önleyebilirsiniz.
  1. Zamanlayıcıyı durdurduğunuz onStop() satırındaki yorum işaretini kaldırın.
  2. startTimer() aralığındaki onStart() çağrısını kesip onCreate() aralığına yapıştırın. Bu değişiklik, onCreate() kullanarak başlatmak yerine hem onCreate() içinde bir kaynağı başlattığınız hem de başlattığınız durumu gösterir.onStart()
  3. Uygulamayı derleyip çalıştırın. Zamanlayıcının beklendiği gibi çalışmaya başladığını fark edin.
  4. Uygulamayı durdurmak için Ana Sayfa'yı tıklayın. Zamanlayıcı, beklendiği gibi durur.
  5. Uygulamaya dönmek için son kullanılanlar ekranını kullanın. Bu durumda, onCreate() yalnızca uygulama başlatıldığında çağrıldığı için zamanlayıcının yeniden başlamadığını unutmayın. Uygulama ön plana döndüğünde çağrılmaz.

Hatırlanması gereken önemli noktalar:

  • Bir yaşam döngüsü geri çağırma işlevinde kaynak ayarladığınızda kaynağı da kapatın.
  • Kurulum ve kaldırma işlemlerini ilgili yöntemlerle yapın.
  • onStart()'da bir şey ayarladıysanız onStop()'da durdurun veya tekrar kaldırın.

DessertClicker uygulamasında, zamanlayıcıyı onStart() içinde başlattıysanız onStop() içinde durdurmanız gerektiği oldukça kolay bir şekilde anlaşılıyor. Yalnızca bir zamanlayıcı olduğundan zamanlayıcıyı durdurmayı unutmazsınız.

Daha karmaşık bir Android uygulamasında, onStart() veya onCreate() içinde birçok şey ayarlayıp onStop() veya onDestroy() içinde hepsini kaldırabilirsiniz. Örneğin, hem ayarlamanız hem de kaldırmanız, hem başlatmanız hem de durdurmanız gereken animasyonlar, müzikler, sensörler veya zamanlayıcılar olabilir. Birini unutursanız hatalara ve sorunlara yol açarsınız.

Android Jetpack'in bir parçası olan Lifecycle kitaplığı bu görevi kolaylaştırır. Kitaplık, özellikle farklı yaşam döngüsü durumlarında olan birçok hareketli parçayı izlemeniz gerektiğinde yararlıdır. Kitaplık, yaşam döngülerinin çalışma şeklini tersine çevirir: Genellikle etkinlik veya parça, bir yaşam döngüsü geri çağırma işlemi gerçekleştiğinde bir bileşene (ör. DessertTimer) ne yapması gerektiğini söyler. Ancak yaşam döngüsü kitaplığını kullandığınızda bileşen, yaşam döngüsü değişikliklerini izler ve bu değişiklikler gerçekleştiğinde gerekenleri yapar.

Yaşam döngüsü kitaplığının üç ana bölümü vardır:

  • Yaşam döngüsüne sahip olan (ve dolayısıyla "sahibi" olan) bileşenler olan yaşam döngüsü sahipleri. Activity ve Fragment, yaşam döngüsü sahipleridir. Yaşam döngüsü sahipleri LifecycleOwner arayüzünü uygular.
  • Yaşam döngüsü sahibinin gerçek durumunu tutan ve yaşam döngüsü değişiklikleri gerçekleştiğinde etkinlikleri tetikleyen Lifecycle sınıfı.
  • Yaşam döngüsü durumunu gözlemleyen ve yaşam döngüsü değiştiğinde görevleri gerçekleştiren yaşam döngüsü gözlemcileri. Yaşam döngüsü gözlemcileri, LifecycleObserver arayüzünü uygular.

Bu görevde, DessertClicker uygulamasını Android yaşam döngüsü kitaplığını kullanacak şekilde dönüştürecek ve kitaplığın Android etkinliği ve parça yaşam döngüleriyle çalışmayı nasıl kolaylaştırdığını öğreneceksiniz.

1. adım: DessertTimer'ı LifecycleObserver'a dönüştürün

Yaşam döngüsü kitaplığının temel bir parçası yaşam döngüsü gözlemi kavramıdır. Gözlem, sınıfların (ör. DessertTimer) etkinlik veya parça yaşam döngüsü hakkında bilgi edinmesini ve bu yaşam döngüsü durumlarındaki değişikliklere yanıt olarak kendilerini başlatıp durdurmasını sağlar. Yaşam döngüsü gözlemcisiyle, nesneleri başlatma ve durdurma sorumluluğunu etkinlik ve parça yöntemlerinden kaldırabilirsiniz.

  1. DesertTimer.kt sınıfını açın.
  2. DessertTimer sınıfının sınıf imzasını şu şekilde değiştirin:
class DessertTimer(lifecycle: Lifecycle) : LifecycleObserver {

Bu yeni sınıf tanımı iki işlevi yerine getirir:

  • Oluşturucu, zamanlayıcının gözlemlediği yaşam döngüsü olan bir Lifecycle nesnesi alır.
  • Sınıf tanımı, LifecycleObserver arayüzünü uygular.
  1. runnable değişkeninin altına sınıf tanımına bir init bloğu ekleyin. init bloğunda, sahibinden (etkinlik) iletilen yaşam döngüsü nesnesini bu sınıfa (gözlemci) bağlamak için addObserver() yöntemini kullanın.
 init {
   lifecycle.addObserver(this)
}
  1. startTimer() öğesini @OnLifecycleEvent annotation ile açıklama olarak ekleyin ve ON_START yaşam döngüsü etkinliğini kullanın. Yaşam döngüsü gözlemcinizin gözlemleyebileceği tüm yaşam döngüsü etkinlikleri Lifecycle.Event sınıfındadır.
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun startTimer() {
  1. stopTimer() için de aynı işlemi yapın ve ON_STOP etkinliğini kullanın:
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopTimer()

2. adım: MainActivity'yi değiştirin

FragmentActivity üst sınıfı LifecycleOwner'yi uyguladığından MainActivity sınıfınız zaten devralma yoluyla yaşam döngüsü sahibidir. Bu nedenle, etkinliğinizin yaşam döngüsünden haberdar olması için herhangi bir işlem yapmanız gerekmez. Tek yapmanız gereken, etkinliğin yaşam döngüsü nesnesini DessertTimer oluşturucusuna iletmektir.

  1. MainActivity adlı kişiyi aç. onCreate() yönteminde, DessertTimer başlatma işlemini this.lifecycle'yi içerecek şekilde değiştirin:
dessertTimer = DessertTimer(this.lifecycle)

Etkinliğin lifecycle özelliği, bu etkinliğin sahibi olduğu Lifecycle nesnesini içerir.

  1. onCreate()'daki startTimer() numaralı telefona yapılan aramayı ve onStop()'daki stopTimer() numaralı telefona yapılan aramayı kaldırın. DessertTimer artık yaşam döngüsünü kendisi gözlemlediği ve yaşam döngüsü durumu değiştiğinde otomatik olarak bilgilendirildiği için etkinlikte DessertTimer'ya ne yapması gerektiğini söylemenize gerek yoktur. Bu geri çağırmalarda artık tek yaptığınız işlem mesaj kaydetmektir.
  2. Uygulamayı derleyip çalıştırın ve Logcat'i açın. Zamanlayıcının beklendiği gibi çalışmaya başladığını fark edin.
  3. Uygulamayı arka plana almak için ana sayfa düğmesini tıklayın. Zamanlayıcının beklendiği gibi durduğunu fark edin.

Android, arka planda çalışan bir uygulamayı kapatırsa uygulamanıza ve verilerine ne olur? Bu zorlu uç durumu anlamak önemlidir.

Uygulamanız arka plana geçtiğinde yok edilmez, yalnızca durdurulur ve kullanıcının uygulamaya dönmesini bekler. Ancak Android işletim sisteminin temel endişelerinden biri, ön plandaki etkinliğin sorunsuz bir şekilde çalışmasını sağlamaktır. Örneğin, kullanıcınız otobüse binmesine yardımcı olması için bir GPS uygulaması kullanıyorsa bu GPS uygulamasını hızlı bir şekilde oluşturmak ve yol tariflerini göstermeye devam etmek önemlidir. Kullanıcının birkaç gündür bakmamış olabileceği DessertClicker uygulamasının arka planda sorunsuz çalışmasını sağlamak daha az önemlidir.

Android, ön plandaki uygulamanın sorunsuz çalışabilmesi için arka plandaki uygulamaları düzenler. Örneğin, Android arka planda çalışan uygulamaların yapabileceği işlem miktarını sınırlar.

Android bazen uygulamanın tüm işlemlerini (uygulamayla ilişkili tüm etkinlikler dahil) kapatır. Android, sistemin zorlandığı ve görsel olarak gecikme tehlikesiyle karşı karşıya olduğu durumlarda bu tür bir kapatma işlemi yapar. Bu nedenle, bu noktada ek geri çağırma veya kod çalıştırılmaz. Uygulamanızın işlemi arka planda sessizce kapatılır. Ancak kullanıcıya göre uygulama kapatılmamış gibi görünür. Kullanıcı, Android işletim sisteminin kapattığı bir uygulamaya geri döndüğünde Android bu uygulamayı yeniden başlatır.

Bu görevde, bir Android işleminin kapatılmasını simüle edip uygulamanız yeniden başlatıldığında neler olduğunu incelersiniz.

1. adım: İşlem kapatmayı simüle etmek için adb'yi kullanın

Android Debug Bridge (adb), bilgisayarınıza bağlı emülatörlere ve cihazlara talimat göndermenize olanak tanıyan bir komut satırı aracıdır. Bu adımda, uygulamanızın sürecini kapatmak ve Android uygulamanızı kapattığında ne olduğunu görmek için adb aracını kullanırsınız.

  1. Uygulamanızı derleyip çalıştırın. Cupcake'i birkaç kez tıklayın.
  2. Uygulamanızı arka plana almak için ana sayfa düğmesine basın. Uygulamanız artık durdurulur ve Android'in uygulamanın kullandığı kaynaklara ihtiyacı olursa uygulama kapatılabilir.
  3. Android Studio'da komut satırı terminalini açmak için Terminal sekmesini tıklayın.
  4. adb yazıp Return tuşuna basın.

    Android Debug Bridge version X.XX.X ile başlayıp tags to be used by logcat (see logcat —help) ile biten çok sayıda çıktı görüyorsanız her şey yolundadır. Bunun yerine adb: command not found simgesini görüyorsanız adb komutunun yürütme yolunuzda kullanılabilir olduğundan emin olun. Talimatlar için Utilities chapter (Yardımcı Programlar bölümü) içindeki "Add adb to your execution path" (adb'yi yürütme yolunuza ekleme) başlıklı makaleye bakın.
  5. Bu yorumu kopyalayıp komut satırına yapıştırın ve Return tuşuna basın:
adb shell am kill com.example.android.dessertclicker

Bu komut, bağlı cihazlara veya emülatörlere dessertclicker paket adıyla işlemi durdurmalarını söyler ancak yalnızca uygulama arka plandaysa. Uygulamanız arka planda olduğundan, işleminizin durdurulduğunu belirten herhangi bir şey cihazda veya emülatör ekranında gösterilmez. Android Studio'da Çalıştır sekmesini tıklayarak "Uygulama sonlandırıldı" mesajını görün. onDestroy() geri çağırma işlevinin hiçbir zaman çalıştırılmadığını (etkinliğinizin sona erdiğini) görmek için Logcat sekmesini tıklayın.

  1. Uygulamaya dönmek için son kullanılanlar ekranını kullanın. Uygulamanız, arka plana alınmış veya tamamen durdurulmuş olsa da son kullanılanlar ekranında görünür. Uygulamaya dönmek için son kullanılanlar ekranını kullandığınızda etkinlik yeniden başlatılır. Etkinlik, onCreate() dahil olmak üzere başlangıç yaşam döngüsü geri çağırmalarının tamamından geçer.
  2. Uygulama yeniden başlatıldığında "puanınızın" (hem satılan tatlı sayısı hem de toplam tutar) varsayılan değerlere (0) sıfırlandığını unutmayın. Android, uygulamanızı kapattıysa neden durumunuzu kaydetmedi?

    İşletim sistemi, uygulamanızı sizin için yeniden başlattığında Android, uygulamanızı önceki durumuna sıfırlamak için elinden geleni yapar. Android, bazı görünümlerinizin durumunu alır ve etkinlikten ayrıldığınızda bunu bir pakete kaydeder. Otomatik olarak kaydedilen verilere örnek olarak EditText'teki metin (düzen içinde bir kimlik ayarlanmış olması koşuluyla) ve etkinliğinizin geri yığını verilebilir.

    Ancak Android işletim sistemi bazen tüm verileriniz hakkında bilgi sahibi olmaz. Örneğin, DessertClicker uygulamasında revenue gibi bir özel değişkeniniz varsa Android işletim sistemi bu veriler veya etkinliğiniz için önemleri hakkında bilgi sahibi değildir. Bu verileri pakete kendiniz eklemeniz gerekir.

2. adım: Paket verilerini kaydetmek için onSaveInstanceState() yöntemini kullanın

onSaveInstanceState() yöntemi, Android işletim sistemi uygulamanızı yok ederse ihtiyacınız olabilecek verileri kaydetmek için kullandığınız geri çağırmadır. Yaşam döngüsü geri çağırma şemasında onSaveInstanceState(), etkinlik durdurulduktan sonra çağrılır. Uygulamanız her arka plana gittiğinde bu işlev çağrılır.

onSaveInstanceState() çağrısını bir güvenlik önlemi olarak düşünebilirsiniz. Etkinliğiniz ön plandan çıktığında küçük bir bilgi miktarını pakete kaydetme fırsatı verir. Sistem, uygulamanızı kapatana kadar beklerse işletim sistemi kaynak baskısı altında kalabileceği için bu verileri şimdi kaydeder. Verilerin her seferinde kaydedilmesi, paketteki güncelleme verilerinin gerektiğinde geri yüklenebilmesini sağlar.

  1. MainActivity içinde onSaveInstanceState() geri çağırmasını geçersiz kılın ve Timber günlük ifadesi ekleyin.
override fun onSaveInstanceState(outState: Bundle) {
   super.onSaveInstanceState(outState)

   Timber.i("onSaveInstanceState Called")
}
  1. Uygulamayı derleyip çalıştırın ve arka plana almak için Ana Sayfa düğmesini tıklayın. onSaveInstanceState() geri çağırmasının onPause() ve onStop():
    hemen ardından gerçekleştiğini unutmayın.
  2. Dosyanın en üstünde, sınıf tanımından hemen önce şu sabitleri ekleyin:
const val KEY_REVENUE = "revenue_key"
const val KEY_DESSERT_SOLD = "dessert_sold_key"
const val KEY_TIMER_SECONDS = "timer_seconds_key"

Bu anahtarları, örnek durumu paketinden veri kaydetmek ve almak için kullanırsınız.

  1. onSaveInstanceState() bölümüne gidin ve Bundle türünde olan outState parametresine dikkat edin.

    Paket, anahtarların her zaman dize olduğu bir anahtar/değer çiftleri koleksiyonudur. Pakete int ve boolean değerleri gibi temel değerler yerleştirebilirsiniz.
    Sistem bu paketi RAM'de tuttuğu için paketteki verileri küçük tutmak en iyi uygulamadır. Bu paketin boyutu da sınırlıdır ancak boyutu cihazdan cihaza değişir. Genellikle 100.000'den çok daha az öğe depolamanız gerekir. Aksi takdirde, uygulamanızın TransactionTooLargeException hatasıyla kilitlenmesi riskiyle karşılaşırsınız.
  2. onSaveInstanceState() içinde, revenue değerini (bir tam sayı) putInt() yöntemiyle pakete yerleştirin:
outState.putInt(KEY_REVENUE, revenue)

putInt() yöntemi (ve Bundle sınıfındaki putFloat() ve putString() gibi benzer yöntemler) iki bağımsız değişken alır: anahtar için bir dize (KEY_REVENUE sabiti) ve kaydedilecek gerçek değer.

  1. Satılan tatlı sayısı ve zamanlayıcının durumu için aynı işlemi tekrarlayın:
outState.putInt(KEY_DESSERT_SOLD, dessertsSold)
outState.putInt(KEY_TIMER_SECONDS, dessertTimer.secondsCount)

3. adım: Paket verilerini geri yüklemek için onCreate() işlevini kullanın

  1. onCreate() simgesine gidin ve yöntem imzasını inceleyin:
override fun onCreate(savedInstanceState: Bundle) {

onCreate() her çağrıldığında Bundle değerini alır. Etkinliğiniz bir işlem kapatma nedeniyle yeniden başlatıldığında, kaydettiğiniz paket onCreate()'a iletilir. Etkinliğiniz yeni başlıyorsa onCreate() içindeki bu paket null. Bu nedenle, paket null değilse etkinliği daha önce bilinen bir noktadan "yeniden oluşturduğunuzu" anlarsınız.

  1. DessertTimer kurulumundan sonra onCreate()'ya şu kodu ekleyin:
if (savedInstanceState != null) {
   revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
}

null testi, pakette veri olup olmadığını veya paketin null olup olmadığını belirler. Bu da uygulamanın sıfırdan başlatılıp başlatılmadığını ya da kapatıldıktan sonra yeniden oluşturulup oluşturulmadığını gösterir. Bu test, paketten veri geri yüklemek için kullanılan yaygın bir yöntemdir.

Burada kullandığınız anahtarın (KEY_REVENUE), putInt() için kullandığınız anahtarla aynı olduğuna dikkat edin. Her seferinde aynı anahtarı kullandığınızdan emin olmak için bu anahtarları sabit olarak tanımlamanız önerilir. Verileri pakete yerleştirmek için putInt() kullandığınız gibi, paketten veri almak için getInt() kullanırsınız. getInt() yöntemi iki bağımsız değişken alır:

  • Anahtar görevi gören bir dize (ör. gelir değeri için "key_revenue").
  • Pakette bu anahtar için değer yoksa varsayılan değer.

Paketten aldığınız tam sayı daha sonra revenue değişkenine atanır ve kullanıcı arayüzü bu değeri kullanır.

  1. Satılan tatlı sayısını ve zamanlayıcının değerini geri yüklemek için getInt() yöntemlerini ekleyin:
if (savedInstanceState != null) {
   revenue = savedInstanceState.getInt(KEY_REVENUE, 0)dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
   dessertTimer.secondsCount =
       savedInstanceState.getInt(KEY_TIMER_SECONDS, 0)
}
  1. Uygulamayı derleyip çalıştırın. Cupcake, donut'a dönüşene kadar en az beş kez basın. Uygulamayı arka plana almak için Ana Sayfa'yı tıklayın.
  2. Uygulamanın sürecini kapatmak için Android Studio Terminal sekmesinde adb komutunu çalıştırın.
adb shell am kill com.example.android.dessertclicker
  1. Uygulamaya dönmek için son kullanılanlar ekranını kullanın. Bu kez uygulamanın, paketteki doğru gelir ve satılan tatlı değerleriyle döndüğünü göreceksiniz. Ancak tatlının da keke döndüğünü fark edin. Uygulamanın kapatıldıktan sonra tam olarak bırakıldığı şekilde geri dönmesini sağlamak için yapılması gereken bir işlem daha var.
  2. MainActivity bölümünde showCurrentDessert() yöntemini inceleyin. Bu yöntemin, satılan tatlıların mevcut sayısına ve allDesserts değişkenindeki tatlı listesine göre etkinlikte hangi tatlı resminin gösterileceğini belirlediğini unutmayın.
for (dessert in allDesserts) {
   if (dessertsSold >= dessert.startProductionAmount) {
       newDessert = dessert
   }
    else break
}

Bu yöntemde, doğru resmi seçmek için satılan tatlıların sayısı kullanılır. Bu nedenle, paketteki resme referans depolamak için onSaveInstanceState() içinde herhangi bir işlem yapmanız gerekmez. Bu pakette, satılan tatlıların sayısını zaten saklıyorsunuz.

  1. onCreate() içinde, paketten durumu geri yükleyen blokta showCurrentDessert() işlevini çağırın:
 if (savedInstanceState != null) {
   revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
   dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
   dessertTimer.secondsCount = 
      savedInstanceState.getInt(KEY_TIMER_SECONDS, 0)
   showCurrentDessert()                   
}
  1. Uygulamayı derleyip çalıştırın ve arka plana alın. İşlemi kapatmak için adb öğesini kullanın. Uygulamaya dönmek için son kullanılanlar ekranını kullanın. Tatlı siparişleri, toplam gelir ve tatlı resmi değerlerinin doğru şekilde geri yüklendiğini unutmayın.

Etkinlik ve parça yaşam döngüsünü yönetirken anlaşılması gereken son bir özel durum vardır: yapılandırma değişikliklerinin etkinliklerinizin ve parçalarınızın yaşam döngüsünü nasıl etkilediği.

Cihazın durumu o kadar radikal bir şekilde değişir ki sistemin bu değişikliği çözmenin en kolay yolu etkinliği tamamen kapatıp yeniden oluşturmaktır. Bu duruma yapılandırma değişikliği denir. Örneğin, kullanıcı cihaz dilini değiştirirse farklı metin yönlerini desteklemek için tüm düzenin değiştirilmesi gerekebilir. Kullanıcı cihazı bir yerleştirme istasyonuna takarsa veya fiziksel bir klavye eklerse uygulama düzeninin farklı bir ekran boyutundan ya da düzenden yararlanması gerekebilir. Cihaz yönü değişirse (ör. cihaz dikeyden yataya veya yataydan dikeye döndürülürse) düzenin yeni yöne uyacak şekilde değiştirilmesi gerekebilir.

1. adım: Cihaz döndürme ve yaşam döngüsü geri çağırmalarını keşfedin

  1. Uygulamanızı derleyip çalıştırın ve Logcat'i açın.
  2. Cihazı veya emülatörü yatay moda döndürün. Döndürme düğmeleriyle veya Control ve ok tuşlarıyla (Mac'te Command ve ok tuşları) emülatörü sola veya sağa döndürebilirsiniz.
  3. Logcat'teki çıkışı inceleyin. Çıkışı MainActivity'ya göre filtreleyin.
    Cihaz veya emülatör ekranı döndürdüğünde sistemin, etkinliği kapatmak için tüm yaşam döngüsü geri çağırmalarını çağırdığını unutmayın. Ardından, etkinlik yeniden oluşturulurken sistem, etkinliği başlatmak için tüm yaşam döngüsü geri çağırmalarını çağırır.
  4. MainActivity içinde onSaveInstanceState() yönteminin tamamını yorum satırı yapın.
  5. Uygulamanızı tekrar derleyip çalıştırın. Kek simgesini birkaç kez tıklayın ve cihazı veya emülatörü döndürün. Bu kez, cihaz döndürüldüğünde ve etkinlik kapatılıp yeniden oluşturulduğunda etkinlik varsayılan değerlerle başlatılır.

    Yapılandırma değişikliği gerçekleştiğinde Android, uygulamanın durumunu kaydetmek ve geri yüklemek için önceki görevde öğrendiğiniz aynı örnek durumu paketini kullanır. İşlem kapatma işleminde olduğu gibi, uygulamanızın verilerini pakete yerleştirmek için onSaveInstanceState() kullanın. Ardından, cihaz döndürülürse etkinlik durumu verilerinin kaybolmasını önlemek için onCreate() içindeki verileri geri yükleyin.
  6. MainActivity içinde onSaveInstanceState() yönteminin yorumunu kaldırın, uygulamayı çalıştırın, cupcake'i tıklayın ve uygulamayı veya cihazı döndürün. Bu kez tatlı verilerinin etkinlik rotasyonu boyunca korunduğunu fark edin.

Android Studio projesi: DessertClickerFinal

Yaşam döngüsüyle ilgili ipuçları

  • Bir yaşam döngüsü geri çağırma işlevinde ayarladığınız veya başlattığınız bir şeyi, ilgili geri çağırma işlevinde durdurun veya kaldırın. Öğeyi durdurarak artık gerekmediğinde çalışmaya devam etmemesini sağlayabilirsiniz. Örneğin, onStart() uygulamasında bir zamanlayıcı ayarlarsanız zamanlayıcıyı onStop() uygulamasında duraklatmanız veya durdurmanız gerekir.
  • onCreate() işlevini yalnızca uygulamanız ilk başlatıldığında bir kez çalışan kısımlarını başlatmak için kullanın. Uygulamanızın hem başlatıldığında hem de her ön plana döndüğünde çalışan bölümlerini başlatmak için onStart() kullanın.

Lifecycle kitaplığı

  • Yaşam döngüsü kontrolünü etkinlikten veya parçadan yaşam döngüsüne duyarlı olması gereken gerçek bileşene kaydırmak için Android yaşam döngüsü kitaplığını kullanın.
  • Yaşam döngüsü sahipleri, Activity ve Fragment dahil olmak üzere yaşam döngülerine sahip olan (ve dolayısıyla "sahibi" olan) bileşenlerdir. Yaşam döngüsü sahipleri LifecycleOwner arayüzünü uygular.
  • Yaşam döngüsü gözlemcileri, mevcut yaşam döngüsü durumuna dikkat eder ve yaşam döngüsü değiştiğinde görevleri gerçekleştirir. Yaşam döngüsü gözlemcileri, LifecycleObserver arayüzünü uygular.
  • Lifecycle nesneleri gerçek yaşam döngüsü durumlarını içerir ve yaşam döngüsü değiştiğinde etkinlikleri tetikler.

Yaşam döngüsüne duyarlı bir sınıf oluşturmak için:

  • Yaşam döngüsünün farkında olması gereken sınıflarda LifecycleObserver arayüzünü uygulayın.
  • Etkinlik veya parçadaki yaşam döngüsü nesnesiyle bir yaşam döngüsü gözlemcisi sınıfını başlatın.
  • Yaşam döngüsü gözlemcisi sınıfında, yaşam döngüsüne duyarlı yöntemleri ilgilendikleri yaşam döngüsü durum değişikliğiyle açıklama ekleyin.

    Örneğin, @OnLifecycleEvent(Lifecycle.Event.ON_START)açıklaması, yöntemin onStart yaşam döngüsü etkinliğini izlediğini gösterir.

İşlem kapatmaları ve etkinlik durumunu kaydetme

  • Android, ön plandaki uygulamanın sorunsuz çalışabilmesi için arka planda çalışan uygulamaları düzenler. Bu düzenleme, arka plandaki uygulamaların yapabileceği işlem miktarını sınırlamayı ve hatta bazen tüm uygulama sürecinizi kapatmayı içerir.
  • Kullanıcı, sistemin arka planda bir uygulamayı kapatıp kapatmadığını anlayamaz. Uygulama, son kullanılanlar ekranında görünmeye devam eder ve kullanıcının bıraktığı durumda yeniden başlatılır.
  • Android Debug Bridge (adb), bilgisayarınıza bağlı emülatörlere ve cihazlara talimat göndermenize olanak tanıyan bir komut satırı aracıdır. Uygulamanızda işlem kapatmayı simüle etmek için adb kullanabilirsiniz.
  • Android, uygulama işleminizi kapattığında onDestroy() yaşam döngüsü yöntemi çağrılmaz. Uygulama durur.

Etkinlik ve parça durumunu koruma

  • Uygulamanız arka plana gittiğinde, onStop() çağrıldıktan hemen sonra uygulama verileri bir pakete kaydedilir. EditText içeriği gibi bazı uygulama verileri sizin için otomatik olarak kaydedilir.
  • Paket, anahtar ve değer koleksiyonu olan Bundle öğesinin bir örneğidir. Anahtarlar her zaman dizedir.
  • Uygulama otomatik olarak kapatılsa bile saklamak istediğiniz diğer verileri pakete kaydetmek için onSaveInstanceState() geri çağırma işlevini kullanın. Pakete veri yerleştirmek için put ile başlayan paket yöntemlerini (ör. putInt()) kullanın.
  • Verileri onRestoreInstanceState() yöntemiyle veya daha yaygın olarak onCreate() yöntemiyle paketten geri alabilirsiniz. onCreate() yönteminde paketi tutan bir savedInstanceState parametresi var.
  • savedInstanceState değişkeni null içeriyorsa etkinlik, durum paketi olmadan başlatılmıştır ve alınacak durum verisi yoktur.
  • Paketten anahtarla veri almak için get ile başlayan Bundle yöntemlerini (ör. getInt()) kullanın.

Yapılandırma değişiklikleri

  • Cihazın durumu o kadar radikal bir şekilde değişir ki sistemin bu değişikliği çözmesinin en kolay yolu etkinliği kapatıp yeniden oluşturmaktır. Bu duruma yapılandırma değişikliği denir.
  • Yapılandırma değişikliğinin en yaygın örneği, kullanıcının cihazı dikey moddan yatay moda veya yatay moddan dikey moda döndürmesidir. Cihazın dili değiştiğinde veya donanım klavyesi takıldığında da yapılandırma değişikliği olabilir.
  • Yapılandırma değişikliği olduğunda Android, etkinlik yaşam döngüsünün tüm kapatma geri çağırmalarını çağırır. Ardından Android, tüm yaşam döngüsü başlangıç geri çağırmalarını çalıştırarak etkinliği baştan başlatır.
  • Android, yapılandırma değişikliği nedeniyle bir uygulamayı kapattığında etkinliği onCreate() için kullanılabilen durum paketiyle yeniden başlatır.
  • İşlem kapatma işleminde olduğu gibi, uygulamanızın durumunu onSaveInstanceState() içindeki pakete kaydedin.

Udacity kursu:

Android geliştirici belgeleri:

Diğer:

Bu bölümde, bir eğitmenin yönettiği kurs kapsamında bu codelab'i tamamlayan öğrenciler için olası ödevler listelenmektedir. Eğitmen, aşağıdakileri yapmalıdır:

  • Gerekirse ödev atayın.
  • Öğrencilere ev ödevi ödevlerini nasıl göndereceklerini bildirin.
  • Ödevlere not verin.

Eğitmenler bu önerileri istedikleri kadar kullanabilir ve uygun olduğunu düşündükleri diğer ödevleri verebilirler.

Bu codelab'i kendi başınıza tamamlıyorsanız bilginizi test etmek için bu ödevleri kullanabilirsiniz.

Uygulamaları değiştirme

1. dersteki DiceRoller uygulamasını açın. (Uygulama yüklü değilse buradan indirebilirsiniz.) Uygulamayı derleyip çalıştırın. Cihazı döndürdüğünüzde zarın geçerli değerinin kaybolduğunu unutmayın. Paketteki değeri korumak ve bu değeri onCreate() içinde geri yüklemek için onSaveInstanceState() öğesini uygulayın.

Bu soruları yanıtlayın

1. Soru

Uygulamanız, gösterilmesi için yoğun hesaplama gerektiren bir fizik simülasyonu içeriyor. Ardından kullanıcı telefonla aranır. Aşağıdaki ifadelerden hangisi doğrudur?

  • Telefon görüşmesi sırasında, fizik simülasyonundaki nesnelerin konumlarını hesaplamaya devam etmelisiniz.
  • Telefon görüşmesi sırasında, fizik simülasyonundaki nesnelerin konumlarını hesaplamayı durdurmanız gerekir.

2. Soru

Uygulama ekranda olmadığında simülasyonu duraklatmak için hangi yaşam döngüsü yöntemini geçersiz kılmalısınız?

  • onDestroy()
  • onStop()
  • onPause()
  • onSaveInstanceState()

3. Soru

Android Lifecycle kitaplığı aracılığıyla bir sınıfın yaşam döngüsünden haberdar olmasını sağlamak için sınıf hangi arayüzü uygulamalıdır?

  • Lifecycle
  • LifecycleOwner
  • Lifecycle.Event
  • LifecycleObserver

4. Soru

Etkinliğinizdeki onCreate() yöntemi hangi durumlarda içinde veri bulunan bir Bundle alır (yani Bundle, null değildir)? Birden fazla yanıt geçerli olabilir.

  • Cihaz döndürüldükten sonra etkinlik yeniden başlatılır.
  • Etkinlik sıfırdan başlatılır.
  • Arka plandan döndükten sonra etkinlik devam ettirilir.
  • Cihaz yeniden başlatılır.

Bir sonraki derse başlayın: 5.1: ViewModel ve ViewModelFactory

Bu kurstaki diğer codelab'lerin bağlantılarını Android Kotlin Hakkında Temel Bilgiler codelab'leri açılış sayfasında bulabilirsiniz.