← Blog'a Dön

Lifecycle Hataları Neden Olur?

Lifecycle Hataları Neden Olur?
En Yaygın Android Hatalarının Ortak Kökü
Android geliştirirken karşılaşılan hataların büyük çoğunluğu birbirinden bağımsız ve rastgele görünür. Bir NullPointerException burada, bir memory leak orada, beklenmedik bir çöküş şurada.
Ama bu hataların kaynaklarını derinlemesine incelediğinizde çoğu zaman aynı noktaya ulaşırsınız: lifecycle yanlış anlaşılmış ya da yanlış kullanılmış.
Bu yazı lifecycle hatalarının neden oluştuğunu ve önlemenin somut yollarını ele alıyor.

Hata 1: Yanlış Yerde Kaynak Almak ve Bırakmak
Lifecycle'ın en temel kuralı simetridir. Hangi callback'te bir kaynağı başlattıysanız, karşılık gelen callback'te onu bırakmanız gerekir.
Bu kural ihlal edildiğinde iki farklı sorun ortaya çıkar.
Kaynağı çok erken bırakırsanız Activity hâlâ görünür ve aktifken kaynak gitmiş olur. Kamera onStop'ta serbest bırakılırsa ama kullanıcı kamera ekranında hâlâ duruyorsa, ekran boş ve kırık kalır.
Kaynağı hiç bırakmazsanız ya da çok geç bırakırsanız memory leak oluşur. onResume'de bir listener kaydedip onPause'da kaldırmayı unutursanız, Activity artık görünmese bile o listener Activity'ye referans tutmaya devam eder.
Çözüm her zaman simetrik düşünmektir. onResume ile onPause bir çift, onStart ile onStop bir çift, onCreate ile onDestroy bir çifttir. Birinde başlattığınız her şeyin karşılığında bir bitiş olmalıdır.

Hata 2: onDestroy'a Güvenmek
onDestroy'un mutlaka çağrılacağına güvenmek çok yaygın ve tehlikeli bir yanılgıdır.
Sistem belleğe ihtiyaç duyduğunda uygulamanın process'ini doğrudan öldürebilir. Bu durumda onDestroy çağrılmaz. Process anında sonlanır. onDestroy'a kritik veri kaydetme işlemi koyduysanız o veri kaybolur.
Kalıcı olması gereken veriler onPause'da ya da daha güvenilir biçimde bir veritabanına kaydedilmelidir. onDestroy yalnızca temizlik işlemleri için kullanılmalı, asla tek kaydetme noktası olmamalıdır.

Hata 3: Configuration Change'i Yönetememek
Ekran döndürme, dil değişikliği ya da pencere boyutu değişikliği gibi configuration change olayları Activity'yi yeniden oluşturur. Bu süreci doğru yönetemeyen uygulamalar farklı biçimlerde bozulur.
En yaygın belirtisi kullanıcının veri kaybetmesidir. Doldurulan form ekran döndürülünce sıfırlanır, yarım kalan yükleme yeniden başlar, seçilen öğe unutulur.
Daha sinsi bir belirtisi ise kaynak sızıntısıdır. Her döndürmede yeni bir Activity oluşturulurken eskisi bir yerlerde tutulmaya devam ediyorsa, birkaç döndürme sonrasında bellekte birden fazla Activity birikir. Bu hem bellek tüketimini artırır hem de tutarsız davranışlara yol açar.
Çözüm ViewModel kullanmak ve küçük veriler için onSaveInstanceState'i doğru uygulamaktır. ViewModel, configuration change boyunca yaşamaya devam eder ve yeni oluşturulan Activity'ye aynı veriyi geri sunar.

Hata 4: Arka Plandan UI Güncellemesi
Uygulamanız arka planda bir ağ isteği başlattı. İstek tamamlandı ama bu sürede kullanıcı başka bir uygulamaya geçti ve Activity artık görünür değil.
Ağ isteğinin callback'i çalıştığında Activity görünmez durumdadır ya da tamamen yok edilmiştir. Bu noktada bir UI güncellemesi yapmaya çalışmak, ya sessizce başarısız olur ya da çökmeye neden olur.
Daha da kötüsü, callback'in içinde Activity'ye bir referans tutuluyorsa bu referans Activity'yi bellekte kilitleyen bir memory leak'e dönüşür.
Kotlin Coroutines bu sorunu lifecycle-aware scope'larla zarif biçimde çözer. viewModelScope ya da lifecycleScope kullanıldığında coroutine, Activity ya da ViewModel yok edildiğinde otomatik olarak iptal edilir. Hayatta olmayan bir bileşene güncelleme gönderme riski ortadan kalkar.

Hata 5: Fragment ve Activity Lifecycle Karışıklığı
Fragment'ların kendi lifecycle'ı vardır ve bu lifecycle Activity'nin lifecycle'ından farklı davranabilir. Bu farklılık gözetilmediğinde garip ve tekrarlanamaz hatalar ortaya çıkar.
En sık karşılaşılan sorun, Fragment'ın View lifecycle'ı ile Fragment'ın kendi lifecycle'ının birbirine karıştırılmasıdır. Fragment yok edilmeden önce View'ı yok edilebilir. View yok edildikten sonra View'a erişmeye çalışmak NullPointerException üretir.
Bu nedenle Fragment içinde UI ile ilgili işlemlerde viewLifecycleOwner kullanmak, Fragment'ın kendi lifecycle'ını kullanmaktan çok daha güvenlidir. Observer ve listener'lar viewLifecycleOwner'a bağlandığında View yok edildiğinde otomatik olarak temizlenir.

Hata 6: Lifecycle Farkında Olmayan Bileşenler
Jetpack öncesi dönemin kodlarında çok yaygındı: ViewModel yoktu, LiveData yoktu, lifecycle-aware component yoktu. Her bileşen lifecycle'ı kendisi takip etmek zorundaydı.
Bu yaklaşım sürdürülemez bir karmaşıklığa yol açıyordu. Her yeni bileşen eklendikçe onStart, onStop, onResume, onPause içindeki kod büyüyor ve hata olasılığı artıyordu.
Modern Android geliştirmede Lifecycle-Aware Components bu sorunu kökten çözüyor. LiveData, ViewModel, StateFlow ile birlikte kullanıldığında bileşenler kendi lifecycle durumlarını kendi içlerinde yönetiyor. Activity ya da Fragment tek tek her bileşeni lifecycle metodlarında yönetmek zorunda kalmıyor.

Lifecycle Hatalarını Erken Yakalamak
Lifecycle hatalarının büyük çoğunluğu geliştirme sürecinde fark edilebilir — eğer doğru araçlar kullanılırsa.
LeakCanary memory leak'leri geliştirme sırasında otomatik olarak yakalar ve nereden kaynaklandığını ayrıntılı biçimde raporlar. Projeye eklenmesi ve çalıştırılması dışında ek bir şey gerektirmez.
Android Studio Memory Profiler heap kullanımını gerçek zamanlı gösterir. Ekran döndürme sırasında bellek sürekli artıyorsa ve GC sonrasında düşmüyorsa, bu bir lifecycle kaynaklı leak'in habercisidir.
StrictMode development build'lerde lifecycle ile ilgili ihlaalleri tespit edip loglayabilir. Özellikle kapatılmamış kaynakları bulmak için kullanışlıdır.

Geliştirici Perspektifinden Bakış
Lifecycle hatalarına karşı en etkili savunma doğru mimariden geçer.
ViewModel ve LiveData ya da StateFlow kombinasyonunu benimseyin. Bu yapı, lifecycle yönetimini büyük ölçüde çerçevenin kendisine devreder ve sizi manuel hata kaynaklarından uzaklaştırır.
Her yeni özellik geliştirdiğinizde şu senaryoları manuel olarak test edin: ekranı döndürün, uygulamayı arka plana alıp geri dönün, telefon görüşmesi simüle edin ve sistemi düşük bellek moduna zorlayın. Bu testler lifecycle hatalarının büyük çoğunluğunu erkenden ortaya çıkarır.
Ve unutmayın: Lifecycle hatalarının çoğu anında çökme üretmez. Sessizce birikir, zaman içinde kullanıcı deneyimini kötüleştirir ve ancak ciddi sorunlara dönüştükten sonra fark edilir. Bu yüzden proaktif yaklaşım her zaman reaktif yaklaşımdan değerlidir.