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şlatıp yavaşlatmadığını nasıl değerlendireceğiniz açıklanmakta ve ortaya çıkabilecek sorunların çözümü için bazı stratejiler sunulmaktadır.

Bu sayfa, View tabanlı düzenlerin iyileştirilmesine odaklanmaktadır. Jetpack Compose performansını iyileştirme hakkında bilgi için Jetpack Compose performansını inceleyin.

Performansı düzenleyin ve ölçün

Oluşturma ardışık düzeni, bir düzen ve ölçme aşaması içerir. Bu aşama sırasında sistem, görünüm hiyerarşinizdeki alakalı öğeleri uygun şekilde konumlandırır. Bu aşamanın ölçüm kısmı, View nesnelerinin boyutlarını ve sınırlarını belirler. Düzen bölümü, View nesnelerinin ekranın neresinde konumlanacağı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 neden olur. Çoğu zaman bu maliyet minimumdur ve performansı önemli ölçüde etkilemez. Ancak bir uygulama View nesne eklediğinde veya kaldırdığında (örneğin, bir RecyclerView nesne bunları geri dönüştürdüğünde veya yeniden kullandığında) daha büyük olabilir. View nesnesinin kısıtlamalarını karşılamak için yeniden boyutlandırmayı düşünmesi gerektiğinde de maliyet daha yüksek olabilir. Örneğin, uygulamanız metni saran bir View nesnesinde SetText() çağrısı yaparsa View öğesinin yeniden boyutlandırması gerekebilir.

Bu gibi durumlar çok uzun sürerse izin verilen 16 ms. içinde bir karenin oluşturulmasını engelleyebilir. Bu da karelerin düşmesine ve animasyonun kalitesinin düşmesine neden olabilir.

Bu işlemleri bir çalışan iş parçacığına taşıyamayacağınız için (uygulamanızın bunları ana iş parçacığında işlemesi gerekir) en iyi yöntem, işlemleri mümkün olduğunca az zaman alacak şekilde optimize etmektir.

Karmaşık düzenleri yönetin

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

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

Düzenin uzun sürmesinin yaygın bir nedeni, View nesne hiyerarşilerinin iç içe yerleştirilmesidir. İç içe yerleştirilmiş her düzen nesnesi, düzen aşamasının maliyetini artırır. Hiyerarşiniz ne kadar düz olursa düzen aşamasının tamamlanması o kadar kısa sürer.

Genellikle hem daha verimli olduğu hem de düzenlerin iç içe yerleştirilmesini azalttığı için, RelativeLayout veya LinearLayout yerine bir ConstraintLayout oluşturmak için Düzen Düzenleyici'yi kullanmanızı öneririz. Bununla birlikte, FrameLayout kullanılarak yapılabilecek 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ıksız LinearLayout görünümlerini kullanarak aynı etkiyi daha düşük maliyetle elde edebilirsiniz. Bununla birlikte, iç içe yerleştirilmiş, ağırlıklı LinearLayout görünümleri kullanıyorsanız düzen maliyeti, sonraki bölümde açıklandığı gibi birden fazla düzen geçişi gerektirdiğinden çok daha yüksek olur.

Ayrıca, liste öğelerinin ayrı ayrı düzenlerini geri dönüştürebileceği ve bu şekilde hem daha verimli hem de kaydırma performansını iyileştirebileceği için ListView yerine RecyclerView kullanmanızı öneririz.

Çifte vergilendirme

Tipik olarak çerçeve, düzeni veya ölçüm aşamasını tek bir geçişte yürütür. Bununla birlikte, bazı karmaşık düzen durumlarında çerçevenin, öğeleri konumlandırmadan önce hiyerarşinin birden çok geçiş gerektiren bölümlerinde birkaç kez iterasyon yapması gerekebilir. Birden fazla düzen ve ölçüm yinelemesi uygulanmasına çift vergi denir.

Örneğin, View nesnelerini 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. Düzen ve ölçüm geçişi yürütülür. Bu geçiş sırasında çerçeve, her alt nesnenin isteğine göre her alt nesnenin konumunu ve boyutunu hesaplar.
  2. İlişkili 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ı sonlandırmak 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şinizde ne kadar fazla düzey bulunursa performans cezası olasılığı o kadar artar.

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

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

  • LinearLayout görünümünü yatay yaparsanız iki kez düzen ve ölçüm geçişi yapılabilir. measureWithLargestChild eklerseniz dikey yönde de çift düzen ve ölçüm geçişi gerçekleşebilir. Bu durumda, çerçevenin uygun boyutlardaki nesneleri çözümlemek için ikinci bir geçiş yapması gerekebilir.
  • GridLayout, göreli konumlandırmaya da izin verir ancak normalde alt görüntülemeler arasındaki konum ilişkilerinin önceden işlenmesiyle çifte vergilendirmeyi önler. Bununla birlikte, düzen ağırlıkları kullanıyorsa veya Gravity sınıfıyla dolduruyorsa ön işlemenin avantajı kaybolur ve kapsayıcı RelativeLayout ise çerçevenin birden fazla geçiş yapması gerekebilir.

Birden fazla düzen ve ölçüm geçişi, performans yükü anlamına gelmez. Ama yanlış yerdeyken yükler oluşturabilirler. Kapsayıcınız için aşağıdaki koşullardan birinin geçerli olduğu durumlarda dikkatli olun:

  • Bu, görünüm hiyerarşinizdeki kök öğedir.
  • Altında derin bir görünüm hiyerarşisi vardır.
  • ListView nesnesindeki alt öğelere benzer şekilde, ekranı dolduran birçok bunun ö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 meydana geldiğini belirlemenize yardımcı olabilir. Bazı araçlar daha az kesin bilgi sağlar ama yararlı ipuçları sağlayabilir.

Perfetto

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

Profil GPU oluşturma

Android 6.0 (API düzeyi 23) ve sonraki sürümleri çalıştıran cihazlarda kullanılabilen cihaz üzerinde Profil GPU oluşturma aracı, performanstaki performans sorunları hakkında somut bilgiler sağlayabilir. Bu araç, her oluşturma karesi için düzen ve ölçü aşamasının ne kadar sürdüğünü görmenize olanak tanır. Bu veriler, çalışma zamanı performans sorunlarını teşhis etmenize ve ele almanız gereken düzen ve ölçüm sorunlarını belirlemenize yardımcı olabilir.

Yakaladığı verilerin grafik temsilinde Profil GPU oluşturma, düzen zamanını temsil etmek için mavi rengi kullanır. 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.

Hav

Android Studio'nun Lint aracı, görünüm hiyerarşisindeki verimsizliklerle ilgili bir fikir edinmenize yardımcı olabilir. Bu aracı kullanmak için şekil 1'de gösterildiği gibi Analiz > Kodu İncele'yi seçin.

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

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

Şekil 2. Lint aracının tanımladığı 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 alandaki belirli konular ve sorunlar hakkında daha fazla bilgi edinmek için Lint belgelerine bakın.

Düzen Denetleyici

Android Studio'nun Düzen İnceleyici aracı, uygulamanızın görünüm hiyerarşisinin görsel bir temsilini sağlar. Bu özellik, belirli bir görünümün ana zincirinin net bir görsel temsilini sunarak uygulamanızın hiyerarşisinde gezinmenin iyi bir yoludur ve uygulamanızın oluşturduğu düzenleri incelemenize olanak tanır.

Layout Inspector'ın sunduğu görünümler, çift vergilendirmeden kaynaklanan performans sorunlarını belirlemeye de yardımcı olabilir. Ayrıca, iç içe yerleştirilmiş düzenlerin derin zincirlerini veya çok sayıda iç içe yerleştirilmiş alt öğenin bulunduğu düzen alanlarını tanımlamanıza da bir yol sağlayabilir. Bu durum, performans maliyetlerine neden olabilir. Bu gibi durumlarda, düzen ve ölçme aşamaları maliyetli olabilir ve performans sorunlarına yol açabilir.

Daha fazla bilgi için Düzen Denetleyici ve Düzen Doğrulama ile düzeninizde hata ayıklama bölümüne bakın.

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

Görünüm hiyerarşilerinden kaynaklanan performans sorunlarının çözülmesinin ardındaki temel kavram, uygulamada zor olabilir. Görünüm hiyerarşilerinin performans cezaları uygulanmasını önlemek için görünüm hiyerarşinizi düzleştirir ve çifte vergilendirmeyi azaltın. Bu bölümde, bu hedeflere ulaşma stratejileri anlatılmaktadır.

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

ConstraintLayout, görünümleri yerleşim içinde 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şisinin düzelmesine yardımcı olabilir. ConstraintLayout kullanılarak hiyerarşileri birleştirmek, diğer düzen türleriyle karşılaştırıldığında genellikle daha basittir.

Geliştiriciler genellikle gereğinden fazla iç içe yerleştirilmiş düzenler kullanır. Örneğin, bir RelativeLayout kapsayıcısı, aynı zamanda bir 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 yerinize işaretleyerek hata ayıklama süresini kısaltabilir.

Birleştirme veya dahil et

Gereksiz iç içe yerleştirilmiş düzenlerin sık karşılaşılan bir nedeni <include> etiketidir. Örneğin, aşağıdaki gibi yeniden kullanılabilir bir düzen tanımlayabilirsiniz:

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

Daha sonra, 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>

Önceki düzen, ilk düzeni gereksiz bir şekilde ikinci düzene yerleştiriyor.

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

Daha ucuz bir düzen kullanın

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

Örneğin, TableLayout işlevinin, birçok konum bağımlılığı olan daha karmaşık bir düzenle aynı işlevi sunduğunu görebilirsiniz. Jetpack kitaplığı ConstraintLayout, RelativeLayout ile benzer işlevler ve daha şık ve etkili düzenler oluşturmaya yardımcı olan daha fazla özellik sunar.