← Blog'a Dön

Android Neden Kasar?

Android Neden Kasar?
Pürüzsüzlüğün Düşmanları
Bir uygulamayı kullanırken yaşanan o ani donma, listeyi kaydırırken hissedilen o hafif takılma, butona bastıktan sonra geçen o garip bekleme — bunların hepsine yazılım dünyasında tek bir isim verilir: jank.
Jank rastgele ortaya çıkmaz. Her kasma bir nedenin sonucudur. Ve o nedeni anlamak hem önlemenin hem de çözmenin başlangıç noktasıdır.

16 Milisaniyenin Tiranlığı
Her şey tek bir rakama bağlıdır: 16 milisaniye.
Çoğu Android cihaz ekranı saniyede 60 kez yeniler. Bu şu anlama gelir: Her frame için sistemin elinde yalnızca 16.67 milisaniye vardır. Bu süre içinde ölçüm, yerleşim, çizim ve GPU aktarımı tamamlanmak zorundadır.
Bu süre aşılırsa frame atlanır. Bir frame atlanırsa kullanıcı onu hisseder. Birkaç frame üst üste atlanırsa uygulama kasıyor izlenimi doğar. Kasma sürekli hale gelirse kullanıcı uygulamayı kötü olarak damgalar ve büyük ihtimalle siler.
120Hz ekranlarda bu süre 8 milisaniyeye iner. Rekta daha da kısalır, tolerans daha da düşer.

Ana Nedenler
UI thread'de ağır iş yapmak kasmanın açık ara en yaygın nedenidir. Ağ isteği, veritabanı sorgusu, büyük dosya okuma, karmaşık hesaplama — bunlar UI thread'de yapıldığında o thread bloke olur. Thread bloke olduğunda çizim durur. Çizim durduğunda frame atlanır.
Bu hatanın sinsi yanı geliştirme sırasında fark edilmemesidir. Güçlü bir geliştirici cihazında hızlıca tamamlanan bir işlem, iki yaşındaki orta sınıf bir cihazda 200 milisaniye sürebilir. Test edilmemiş cihaz profilleri, production'da kasma olarak geri döner.
Aşırı derin View hiyerarşisi ölçüm ve yerleşim aşamalarını ağırlaştırır. Her View hiyerarşi ağacı yukarıdan aşağıya ölçülür, sonra aşağıdan yukarıya raporlanır. İç içe geçmiş her katman bu hesabı büyütür. Beş katman derin bir LinearLayout içinde, her katmanda birkaç View ile tasarlanmış bir ekran, bu hesabın maliyetini onlarca kata çıkarabilir.
Gereksiz nesne üretimi Garbage Collector'ı meşgul eder. Her GC döngüsü kısa da olsa UI thread'i duraklatır. Bu duraksamalar tek başına hissedilmeyebilir ama animasyon sırasında ya da liste kaydırmasında birikimleri kasma olarak belirginleşir. Özellikle onDraw içinde ve RecyclerView adaptörlerinde gereksiz nesne yaratmak bu sorunu en çok tetikleyen noktalardır.
Overdraw aynı pikselin birden fazla kez çizilmesidir. Üst üste katmanlanmış View'lar, gereksiz arka plan tanımlamaları, şeffaf katmanların birikmesi — bunlar GPU'yu fazladan çalıştırır. GPU her pikseli bir kez çizmek yerine üç dört kez çiziyorsa frame süresi uzar.
Bellek baskısı dolaylı ama etkili bir kasma kaynağıdır. Uygulama çok fazla bellek tuttuğunda Garbage Collector sıklaşır, Low Memory Killer baskı kurar ve sistem kaynakları önceliklendirme için çaba harcar. Bütün bunlar UI döngüsüne dokunur.
Senkron disk erişimi sıkça göz ardı edilir. SharedPreferences'ı UI thread'de okumak, SQLite sorgusunu main thread'de çalıştırmak, büyük bir dosyadan senkron veri çekmek — disk işlemleri ağ kadar dramatik olmasa da yeterince yavaş ve tahmin edilemezdir.

Kasmanın Farklı Yüzleri
Her kasma aynı görünmez ve aynı nedenden kaynaklanmaz.
Liste kaydırmasında yaşanan kasma genellikle RecyclerView adaptöründe ağır iş yapılmasından kaynaklanır. Her öğe ekrana gelirken yapılan ağ isteği, büyük görsel decode işlemi ya da karmaşık View inflate süreci bu kasmanın tipik tetikleyicileridir.
Ekrana ilk girişte yaşanan kasma çoğunlukla Application ya da Activity onCreate'indeki ağır başlangıç işlemlerinden kaynaklanır. Lazy initialization bu sorunu çözmenin en doğal yoludur.
Animasyon sırasında yaşanan kasma ise çoğunlukla animasyonun UI thread üzerinde çalışmasından ya da animasyonla eş zamanlı gerçekleşen ağır işlemlerden kaynaklanır.

Geliştirici Perspektifinden Bakış
Kasmanın kaynağını bulmak tahmin işi değildir. Android Studio Profiler bu iş için tasarlanmıştır. CPU Profiler, hangi metodun ne kadar zaman harcadığını frame bazlı gösterir. Systrace, frame sürelerini ve thread davranışını nanosaniye hassasiyetiyle görselleştirir.
Developer Options'daki "Show GPU Overdraw" ve "Debug GPU Overdraw" seçenekleri overdraw kaynaklı kasmaları görünür kılar. Kırmızı bölgeler acil müdahale gerektiren noktalardır.
Kasma bir semptomun adıdır, sorunun kendisi değil. Semptomu görmek kolaydır, nedenini bulmak ölçüm gerektirir.