Performans ve hiyerarşileri görüntüleme

View nesnelerinizin hiyerarşisini yönetme şekliniz, uygulamanızın performansını önemli ölçüde etkileyebilir. Bu sayfada, görünüm hiyerarşinizin uygulamanızı yavaşlattığına dair değerlendirmenin nasıl yapılacağı açıklanmakta ve ortaya çıkabilecek sorunları gidermek için bazı stratejiler sunulmaktadır.

Bu sayfada, View tabanlı düzenleri iyileştirmeye odaklanılmıştır. Jetpack Compose performansını iyileştirme hakkında bilgi edinmek için Jetpack Compose performansı'na bakın.

Performansı düzenleyip ölçme

Oluşturma ardışık düzeni, sistemin ilgili öğeleri görüntüleme hiyerarşinizde uygun şekilde konumlandırdığı bir düzenleme ve ölçme aşaması içerir. Bu aşamanın ölçü kısmı, View nesnelerinin boyutlarını ve sınırlarını belirler. Düzen bölümü, View nesnelerinin ekranın neresinde konumlandırılacağını belirler.

Bu ardışık düzen aşamalarının her ikisi de, işledikleri görüntüleme veya düzen başına düşük bir maliyete sahiptir. Çoğu durumda bu maliyet minimum düzeydedir ve performansı önemli ölçüde etkilemez. Bununla birlikte, bir uygulamanın View nesneleri eklemesi veya kaldırması (ör. RecyclerView nesnesinin bunları geri dönüştürmesi veya yeniden kullanması) için bu sayı daha fazla olabilir. Bir View nesnesi, kısıtlamalarını karşılamak için yeniden boyutlandırmayı dikkate alırsa maliyet daha da yüksek olabilir. Örneğin, uygulamanız metni sarmalayan bir View nesnesinde SetText() yöntemini çağırıyorsa View öğesinin yeniden boyutlandırması gerekebilir.

Bu gibi durumlar çok uzun sürerse bir karenin izin verilen 16 ms içinde oluşturulmasını engelleyebilir. Bu da karelerin atlanmasına ve animasyonun sarsıntılı olmasına neden olabilir.

Bu işlemleri bir işleyici iş parçacığına taşıyamazsınız (uygulamanız bunları ana iş parçacığında işlemelidir). Bu nedenle, mümkün olduğunca az zaman almaları için bu işlemleri optimize etmeniz en iyisidir.

Karmaşık düzenleri yönetme

Android Düzenleri, kullanıcı arayüzü nesnelerini görünüm hiyerarşisinde iç içe yerleştirmenize olanak tanır. Bu iç içe yerleştirme, düzen maliyeti de getirebilir. Uygulamanız bir nesneyi düzen için işlediğinde aynı işlemi düzenin tüm alt öğelerinde de gerçekleştirir.

Karmaşık bir düzende, bazen yalnızca sistem düzeni ilk kez hesapladığında maliyet oluşur. Örneğin, uygulamanız bir RecyclerView nesnesindeki karmaşık bir liste öğesini geri dönüştürdüğünde, sistemin tüm nesneleri yerleştirmesi gerekir. Başka bir örnekte, önemsiz değişiklikler üst öğe boyutunu etkilemeyen bir nesneye ulaşana kadar zinciri üst öğeye doğru yayabilir.

Düzenin uzun sürmesinin yaygın nedenlerinden biri, View nesnelerinin hiyerarşileri birbirinin içine yerleştirildiğinde ortaya çıkar. İç içe yerleştirilmiş her düzen nesnesi, düzen aşamasına maliyeti ekler. Hiyerarşiniz ne kadar düz olursa düzen aşamasının tamamlanması o kadar kısa sürer.

Genellikle daha verimli olduğu ve düzenlerin iç içe yerleştirilmesini azalttığı için RelativeLayout veya LinearLayout yerine ConstraintLayout oluşturmak için Düzen Düzenleyici'yi kullanmanızı öneririz. Ancak FrameLayout kullanılarak elde edilebilecek basit düzenler için FrameLayout kullanmanızı öneririz.

RelativeLayout sınıfını kullanıyorsanız bunun yerine iç içe yerleştirilmiş, ağırlıklandırılmamış LinearLayout görünümleri kullanarak aynı etkiyi daha düşük maliyetle elde edebilirsiniz. Ancak, iç içe yerleştirilmiş, ağırlıklı LinearLayout görünümleri kullanıyorsanız sonraki bölümde açıklandığı gibi birden fazla düzen geçişi gerektirdiğinden düzen maliyeti çok daha yüksektir.

Ayrıca, tek tek liste öğelerinin düzenlerini geri dönüştürebileceği için ListView yerine RecyclerView kullanmanızı öneririz. Bu yöntem, hem daha verimli hem de kaydırma performansını artırabilir.

Çifte vergilendirme

Genellikle çerçeve, düzen veya ölçüm aşamasını tek bir geçişte yürütür. Ancak bazı karmaşık düzen durumlarında, çerçevenin öğeleri nihai olarak yerleştirmeden önce çözüme ulaşması için hiyerarşinin birden fazla geçiş gerektiren bölümlerinde birden çok kez iterasyon yapması gerekebilir. Birden fazla düzen ve ölçüm iterasyonu gerçekleştirmek zorunda kalmak çifte vergilendirme olarak adlandırılır.

Örneğin, View nesneyi diğer View nesnelerinin konumlarına göre konumlandırmanıza olanak tanıyan RelativeLayout kapsayıcısını kullandığınızda çerçeve aşağıdaki sırayı gerçekleştirir:

  1. Bir düzen ve ölçüm geçişi yürütür. Bu geçiş sırasında çerçeve, her alt nesnenin isteğini temel alarak her alt nesnenin konumunu ve boyutunu hesaplar.
  2. İlişkilendirilmiş görünümlerin doğru konumunu belirlemek için bu verileri, nesne ağırlıklarını dikkate alarak kullanır.
  3. Nesnelerin konumlarını kesinleştirmek için ikinci bir düzen geçişi gerçekleştirir.
  4. Oluşturma işleminin bir sonraki aşamasına geçer.

Görünüm hiyerarşiniz ne kadar seviyeye sahipse performans cezası olasılığı o kadar artar.

Daha önce de belirtildiği gibi, ConstraintLayout genellikle FrameLayout hariç diğer düzenlerden daha verimlidir. Birden fazla düzen geçişine daha az eğilimlidir ve çoğu durumda düzenleri iç içe yerleştirme ihtiyacını ortadan kaldırır.

RelativeLayout dışındaki kapsayıcılar da çifte vergilendirmeyi artırabilir. Örneğin:

  • LinearLayout görünümünü yatay yaparsanız çift düzen ve ölçüm geçişine neden olabilir. measureWithLargestChild eklerseniz dikey yönde de çift düzen ve ölçüm geçişi gerçekleşebilir. Bu durumda, çerçevenin nesnelerin doğru boyutlarını çözmek için ikinci bir geçiş yapması gerekebilir.
  • GridLayout, göreli konumlandırmaya da izin verir ancak normalde alt görünümler arasındaki konumsal ilişkilerin önceden işlenmesiyle çifte vergilendirmenin önüne geçer. Ancak düzende Gravity sınıfıyla ağırlıklar veya doldurma kullanılıyorsa ön işleme avantajı kaybedilir ve kapsayıcı bir RelativeLayout ise çerçevenin birden fazla geçiş yapması gerekebilir.

Birden fazla düzen ve ölçüm geçişi her zaman bir performans yükü değildir. Ancak yanlış yerde olduklarında yük haline gelebilirler. Kapsayıcınız için aşağıdaki koşullardan birinin geçerli olduğu durumlarda dikkatli olun:

  • Görünüm hiyerarşinizdeki bir kök öğedir.
  • Bunun altında derin bir görünüm hiyerarşisi vardır.
  • ListView nesnesinde çocuklara benzer şekilde ekranı dolduran birçok örneği vardır.

Görünüm hiyerarşisi sorunlarını teşhis etme

Düzen performansı, birçok yönü olan karmaşık bir sorundur. Aşağıdaki araçlar, performans sorunlarının nerede yaşandığını belirlemenize yardımcı olabilir. Bazı araçlar daha az kesin bilgiler verse de faydalı ipuçları sağlayabilir.

Perfetto

Perfetto, performans hakkında veri sağlayan bir araçtır. Android izlemelerini Perfetto kullanıcı arayüzünde açabilirsiniz.

Profil GPU oluşturma

Android 6.0 (API düzeyi 23) ve sonraki sürümlerin yüklü olduğu cihazlarda kullanılabilen cihaz üzerinde GPU oluşturma profilini görüntüleme aracı, performans darboğazları hakkında size somut bilgiler sağlayabilir. Bu araç, her bir oluşturma karesi için düzen ve ölçüm aşamasının ne kadar sürdüğünü görmenizi sağlar. Bu veriler, çalışma zamanı performans sorunlarını teşhis etmenize ve hangi düzen ve ölçüm sorunlarını ele almanız gerektiğini belirlemenize yardımcı olabilir.

Profil GPU oluşturma, yakaladığı verilerin görsel temsilinde mavi rengi kullanarak sayfa düzeni süresini gösterir. Bu aracın nasıl kullanılacağı hakkında daha fazla bilgi için Profil GPU oluşturma hızı bölümüne bakın.

Tiftik

Android Studio'nun Lint aracı, görünüm hiyerarşisindeki verimsizlikleri anlamanıza yardımcı olabilir. Bu aracı kullanmak için Şekil 1'de gösterildiği gibi Analizin > Kodu İncele'yi seçin.

Şekil 1. Android Studio'da Kodu Denetle'yi seçin.

Çeşitli düzen öğeleriyle ilgili bilgiler Android > Lint > Performans bölümünde görünür. Daha fazla ayrıntı görmek için her öğeyi tıklayarak genişletin ve ekranın sağ tarafındaki bölmede daha fazla bilgi görüntüleyin. Şekil 2'de genişletilmiş bilgilere örnek gösterilmektedir.

Şekil 2. Lint aracının tespit ettiği belirli sorunlarla ilgili bilgileri görüntüleme

Bir öğeyi tıkladığınızda sağdaki bölmede bu öğeyle ilişkili sorunlar gösterilir.

Bu bölgedeki belirli konu ve sorunlar hakkında daha fazla bilgi edinmek için Lint belgelerini inceleyin.

Layout Inspector

Android Studio'nun Düzen İnceleyici aracı, uygulamanızın görünüm hiyerarşisinin görsel bir temsilini sağlar. Belirli bir görünümün üst zincirinin net bir görsel temsilini sunarak uygulamanızın hiyerarşisinde gezinmek için iyi bir yoldur ve uygulamanızın oluşturduğu düzenleri incelemenize olanak tanır.

Düzen Denetleyici'nin sunduğu görünümler, çift vergilendirmeden kaynaklanan performans sorunlarını tanımlamaya da yardımcı olabilir. Ayrıca, performans maliyetlerinin kaynağı olabilecek çok sayıda iç içe yerleştirilmiş alt öğe içeren iç içe yerleştirilmiş düzen zincirlerini veya düzen alanlarını belirlemenize de yardımcı olabilir. Böyle durumlarda, düzen ve ölç aşamaları maliyetli olabilir ve performans sorunlarına neden olabilir.

Daha fazla bilgi için Düzen Denetleyici ve Düzen Doğrulaması ile düzeninizde hata ayıklama başlıklı makaleyi inceleyin.

Görünüm hiyerarşisi sorunlarını çözme

Görünüm hiyerarşilerinden kaynaklanan performans sorunlarının çözülmesinin arkasındaki temel kavram uygulamada zor olabilir. Görünüm hiyerarşileri nedeniyle performans cezaları almamak için görünüm hiyerarşinizi düzleştirmeniz ve çifte vergilendirmeyi azaltmanız gerekir. Bu bölümde bu hedeflere ulaşmak için stratejiler yer almaktadır.

Gereksiz iç içe yerleştirilmiş düzenleri kaldırma

ConstraintLayout, görünüm içinde görünümleri konumlandırmak için çok sayıda farklı mekanizmaya sahip bir Jetpack kitaplığıdır. Bu, bir ConstaintLayout öğesini iç içe yerleştirme ihtiyacını azaltır ve görünüm hiyerarşisini düzeltmeye yardımcı olabilir. Diğer düzen türlerine kıyasla ConstraintLayout kullanarak hiyerarşileri düzleştirmek genellikle daha kolaydır.

Geliştiriciler genellikle ihtiyaç duyulandan daha fazla iç içe yerleşik düzen kullanır. Örneğin, bir RelativeLayout kapsayıcısı, aynı zamanda RelativeLayout kapsayıcısı olan tek bir alt öğe içerebilir. Bu iç içe yerleştirme gereksizdir ve görünüm hiyerarşisine gereksiz maliyet ekler. Lint, bu sorunu sizin için işaretleyerek hata ayıklama süresini kısaltabilir.

Birleştirmeyi benimse veya dahil et

Gereksiz iç içe yerleştirilmiş düzenlerin sıkça görülen bir nedeni <include> etiketidir. Örneğin, yeniden kullanılabilir bir düzeni aşağıdaki gibi tanımlayabilirsiniz:

<LinearLayout>
    <!-- some stuff here -->
</LinearLayout>

Ardından, aşağıdaki öğeyi üst kapsayıcıya eklemek için bir <include> etiketi ekleyebilirsiniz:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/app_bg"
    android:gravity="center_horizontal">

    <include layout="@layout/titlebar"/>

    <TextView android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:text="@string/hello"
              android:padding="10dp" />

    ...

</LinearLayout>

Yukarıdaki, ilk düzeni ikinci düzenin içine gereksiz yere yerleştirir.

<merge> etiketi bu sorunu önlemeye yardımcı olabilir. Bu etiket hakkında bilgi için <merge> etiketini kullanma bölümüne bakın.

Daha ucuz bir düzen benimseyin

Mevcut düzen şemanızı, gereksiz düzenler içermeyecek şekilde ayarlayamayabilirsiniz. Bazı durumlarda tek çözüm, tamamen farklı bir düzen türüne geçiş yaparak hiyerarşinizi düzeltmek olabilir.

Örneğin, TableLayout'ün birçok konumsal bağımlılığa sahip daha karmaşık bir düzenle aynı işlevi sağladığını görebilirsiniz. Jetpack kitaplığı ConstraintLayout, RelativeLayout'a benzer işlevlerin yanı sıra daha düz ve daha verimli düzenler oluşturmanıza yardımcı olacak daha fazla özellik sunar.