Donanım hızlandırma

Android 3.0'dan (API düzeyi 11) itibaren Android 2D oluşturma ardışık düzeni, donanım hızlandırmayı destekler. Diğer bir deyişle, bir View zemininde gerçekleştirilen tüm çizim işlemleri GPU'yu kullanır. Donanım hızlandırmayı etkinleştirmek için gereken kaynakların artması nedeniyle uygulamanız daha fazla RAM kullanır.

Hedef API düzeyiniz >=14 ise donanım hızlandırma varsayılan olarak etkindir ancak açıkça etkinleştirilebilir. Uygulamanız yalnızca standart görünümler ve Drawable öğeleri kullanıyorsa uygulamayı genel olarak etkinleştirmek, herhangi bir olumsuz çizim etkisine yol açmaz. Ancak donanım hızlandırma tüm 2D çizim işlemlerinde desteklenmediğinden bu özelliğin etkinleştirilmesi, bazı özel görünümlerinizi veya çizim çağrılarınızı etkileyebilir. Sorunlar genellikle görünmez öğeler, istisnalar veya yanlış oluşturulmuş pikseller olarak kendilerini gösterir. Android bu sorunu düzeltmek için donanım hızlandırmayı birden çok düzeyde etkinleştirme veya devre dışı bırakma seçeneği sunar. Donanım hızlandırmayı kontrol etme başlıklı makaleye bakın.

Uygulamanız özel çizimler yapıyorsa sorunları bulmak için uygulamanızı donanım hızlandırmanın etkin olduğu gerçek donanım cihazlarında test edin. Çizim işlemleri için destek bölümünde donanım hızlandırmayla ilgili bilinen sorunlar ve bunların çözümleriyle ilgili açıklamalar yer alır.

Çerçeve API'leri ile OpenGL ve Renderscript'i de inceleyin

Donanım hızlandırmayı kontrol etme

Donanım hızlandırmayı aşağıdaki düzeylerde denetleyebilirsiniz:

  • Başvuru
  • Etkinlik
  • Pencere
  • Göster

Uygulama düzeyi

Android manifest dosyanızda, uygulamanızın tamamında donanım hızlandırmayı etkinleştirmek için <application> etiketine aşağıdaki özelliği ekleyin:

<application android:hardwareAccelerated="true" ...>

Etkinlik düzeyi

Uygulamanız, genel olarak açık donanım hızlandırmayla düzgün şekilde çalışmazsa bu özelliği bağımsız etkinlikler için de denetleyebilirsiniz. Etkinlik düzeyinde donanım hızlandırmayı etkinleştirmek veya devre dışı bırakmak amacıyla <activity> öğesi için android:hardwareAccelerated özelliğini kullanabilirsiniz. Aşağıdaki örnekte donanım hızlandırmanın tüm uygulama için etkinleştirilmesi ancak bir etkinlik için devre dışı bırakılması söz konusudur:

<application android:hardwareAccelerated="true">
    <activity ... />
    <activity android:hardwareAccelerated="false" />
</application>

Pencere seviyesi

Daha da ayrıntılı denetime ihtiyacınız varsa aşağıdaki kodu kullanarak belirli bir pencere için donanım hızlandırmayı etkinleştirebilirsiniz:

Kotlin

window.setFlags(
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
)

Java

getWindow().setFlags(
    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

Not: Şu anda donanım hızlandırmayı pencere düzeyinde devre dışı bırakamazsınız.

Görünüm düzeyi

Aşağıdaki kodu kullanarak, çalışma zamanında tek bir görünüm için donanım hızlandırmayı devre dışı bırakabilirsiniz:

Kotlin

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)

Java

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Not: Şu anda donanım hızlandırmayı görünüm düzeyinde etkinleştiremezsiniz. Katmanları görüntüleyin, donanım hızlandırmayı devre dışı bırakmak dışında başka işlevlere sahiptir. Kullanımları hakkında daha fazla bilgi için Katmanları görüntüleme konusuna bakın.

Bir görüntülemenin donanım hızlandırmalı olup olmadığını belirleme

Bir uygulamanın, özellikle de özel görünümler gibi konularda şu anda donanım hızlandırmalı olup olmadığını bilmek bazen faydalı olur. Bu, özellikle uygulamanız çok sayıda özel çizim yapıyorsa ve tüm işlemler yeni oluşturma ardışık düzeni tarafından düzgün bir şekilde desteklenmiyorsa yararlıdır.

Uygulamanın donanım hızlandırmalı olup olmadığını kontrol etmenin iki farklı yolu vardır:

Bu kontrolü çizim kodunuzda yapmanız gerekirse mümkünse View.isHardwareAccelerated() yerine Canvas.isHardwareAccelerated() kodunu kullanın. Görünüm, donanım hızlandırmalı pencereye eklendiğinde donanım harici hızlandırılmış Tuval kullanılarak çizilebilir. Bu durum, örneğin önbelleğe alma amacıyla bir bit eşlem içine görünüm çizerken yapılır.

Android çizim modelleri

Donanım hızlandırma etkinleştirildiğinde Android çerçevesi uygulamanızı ekranda oluşturmak için görünen listelerden yararlanan yeni bir çizim modeli kullanır. Ekran listelerini ve bu listelerin uygulamanızı nasıl etkileyebileceğini tam olarak anlamak için, Android'in donanım hızlandırma olmadan nasıl görüntüleme çektiğini de anlamanız faydalı olacaktır. Aşağıdaki bölümlerde yazılım tabanlı ve donanım hızlandırmalı çizim modelleri açıklanmaktadır.

Yazılım tabanlı çizim modeli

Yazılım çizim modelinde görünümler aşağıdaki iki adımla çizilir:

  1. Hiyerarşiyi geçersiz kılın
  2. Hiyerarşiyi çizme

Bir uygulamanın, kullanıcı arayüzünün bir bölümünü güncellemesi gerektiğinde, içeriği değişen her görünümde invalidate() (veya varyantlarından birini) çağırır. Geçersiz kılma mesajları, ekranın yeniden çizilmesi gereken bölgelerinin (kirli bölge) hesaplanması için görünüm hiyerarşisinin en üstüne kadar yayılır. Daha sonra Android sistemi, hiyerarşide kirli bölgeyle kesişen herhangi bir görünümü çizer. Maalesef bu çizim modelinin iki dezavantajı vardır:

  • Öncelikle, bu modelin her çizim geçişinde çok sayıda kod yürütülmesi gerekir. Örneğin, uygulamanız bir düğmede invalidate() işlevini çağırıyorsa ve bu düğme başka bir görünümün üzerinde yer alıyorsa Android sistemi, görünümü değişmemiş olsa bile yeniden çizer.
  • İkinci sorun, çizim modelinin uygulamanızdaki hataları gizleyebilmesidir. Android sistemi, görünümleri kirli bölgeyle kesiştiğinde yeniden çizdiğinden, invalidate() çağrılmasa bile içeriğini değiştirdiğiniz bir görünüm yeniden çizilebilir. Böyle bir durumda, uygun davranışı elde etmek için başka bir görünümün geçersiz kılınacağına güvenirsiniz. Bu davranış, uygulamanızı her değiştirdiğinizde değişebilir. Bu nedenle, görünümün çizim kodunu etkileyen verileri veya durumu değiştirdiğinizde özel görünümlerinizde her zaman invalidate() yöntemini çağırmanız gerekir.

Not: Android görünümleri, arka plan rengi veya TextView içindeki metin gibi özellikleri değiştiğinde invalidate() öğesini otomatik olarak çağırır.

Donanım hızlandırmalı çizim modeli

Android sistemi, ekran güncelleme isteğinde bulunmak ve görünüm oluşturmak için invalidate() ve draw() özelliklerini kullanmaya devam eder ancak gerçek çizimi farklı şekilde işler. Android sistemi, çizim komutlarını hemen çalıştırmak yerine bunları görünüm hiyerarşisinin çizim kodunun çıkışını içeren görüntü listeleri içine kaydeder. Diğer bir optimizasyon da Android sisteminin yalnızca bir invalidate() aramasıyla kirli olarak işaretlenen görünümlerin görüntüleme listelerini kaydedip güncellemesinin gerekmesidir. Geçersiz kılınmamış görüntülemeler, sadece daha önce kaydedilen görüntüleme listesi yeniden düzenlenerek tekrar çekilebilir. Yeni çizim modeli üç aşamadan oluşur:

  1. Hiyerarşiyi geçersiz kılın
  2. Görünen listeleri kaydetme ve güncelleme
  3. Ekran listelerini çizin

Bu modelde, draw() yönteminin yürütülmesi için kirli bölgeyle kesişen bir görünüme güvenemezsiniz. Android sisteminin bir görünümün görüntüleme listesini kaydettiğinden emin olmak için invalidate() işlevini çağırmanız gerekir. Bunu yapmayı unutmak, görünümün değiştirildikten sonra bile aynı görünmesine neden olur.

Alfa veya rotasyon gibi belirli özelliklerin ayarlanması, hedeflenen görünümün geçersiz kılınmasını gerektirmediğinden (bu işlem otomatik olarak yapılır), görüntülü listeleri kullanmak animasyon performansına da fayda sağlar. Bu optimizasyon, görüntüleme listeleri olan görünümler (uygulamanızın donanım hızlandırmalı olduğu tüm görünümler) için de geçerlidir. Örneğin, Button üzerinde ListView içeren bir LinearLayout bulunduğunu varsayalım. LinearLayout öğesinin görünen listesi şu şekildedir:

  • DrawDisplayList(Liste Görünümü)
  • DrawDisplayList(Düğme)

Şimdi ListView opaklığını değiştirmek istediğinizi varsayalım. ListView üzerinde setAlpha(0.5f) çağrısı yapıldıktan sonra, görüntüleme listesi artık şunu içerir:

  • SaveKatmanAlpha(0,5)
  • DrawDisplayList(Liste Görünümü)
  • Geri yükle
  • DrawDisplayList(Düğme)

ListView öğesinin karmaşık çizim kodu yürütülmedi. Bunun yerine, sistem yalnızca çok daha basit olan LinearLayout görüntüleme listesini güncelledi. Donanım hızlandırmanın etkinleştirilmediği bir uygulamada hem listenin hem de üst öğesinin çizim kodu tekrar yürütülür.

Çizim işlemleri için destek

Donanım hızlandırıldığında 2D oluşturma ardışık düzeni, en yaygın kullanılan Canvas çizim işlemlerinin yanı sıra daha az kullanılan birçok işlemi de destekler. Android ile birlikte gelen uygulamaları oluşturmak için kullanılan tüm çizim işlemleri, varsayılan widget'lar ve düzenler, yansımalar ve döşenmiş dokular gibi yaygın gelişmiş görsel efektler desteklenir.

Aşağıdaki tabloda, API düzeylerinde çeşitli işlemlerin destek düzeyleri açıklanmaktadır:

Desteklenen ilk API düzeyi
Kanvas
drawBitmapMesh() (renk dizisi) 18
çizim Resimi() 23
drawPosText() 16
drawTextOnPath() 16
drawVertices() 29
setDrawFilter() 16
klipPath() 18
klipRegion() 18
klipRect(Bölge.Op.XOR) 18
klipRect(Region.Op.koleksiyon) 18
klipRect(Region.Op.Reverse kanallara) 18
Döndürme/perspektif ile klipRect() 18
Boyama yapın
setAntiAlias() (metin için) 18
setAntiAlias() (satırlar için) 16
setFilterBitmap() 17
setDoğrusalText()
setMaskFilter()
setPathEffect() (satırlar için) 28
setShadowtier() (metin hariç) 28
setStrokeCap() (satırlar için) 18
setStrokeCap() (puanlar için) 19
setSubpixelText() 28
Xfermode
PorterDuff.Mode.DARKEN (çerçeve arabelleği) 28
PorterDuff.Mode.LIGHTEN (çerçeve arabelleği) 28
PorterDuff.Mode.OVERLAY (çerçeve arabelleği) 28
Gölgelendirici
ComposeShader'da ComposeShader 28
ComposeShader içinde aynı türde gölgelendiriciler 28
ComposeShader'da yerel matris 18

Tuval ölçeklendirme

Donanım hızlandırmalı 2D oluşturma ardışık düzeni, öncelikle ölçeklendirilmemiş çizimi destekleyecek şekilde geliştirilmiştir. Bazı çizim işlemleri, daha yüksek ölçekli değerlerde kaliteyi önemli ölçüde düşürür. Bu işlemler 1, 0 ölçeğinde çizilen ve GPU tarafından dönüştürülen dokular olarak uygulanır. API düzeyi 28'den itibaren tüm çizim işlemleri sorunsuz olarak ölçeklendirilebilir.

Aşağıdaki tabloda, büyük ölçeklerin doğru şekilde işlenmesi için uygulamanın ne zaman değiştirildiği gösterilmektedir:
Ölçeklendirilecek çizim işlemi Desteklenen ilk API düzeyi
drawText() 18
drawPosText() 28
drawTextOnPath() 28
Basit Şekiller* 17
Karmaşık Şekiller* 28
drawPath() 28
Gölge katmanı 28

Not: "Basit" şekiller, PathEct'e sahip olmayan ve varsayılan olmayan birleştirmeler içermeyen (setStrokeJoin() / setStrokeMiter() ile) bir Paint ile verilmiş drawRect(), drawCircle(), drawOval(), drawRoundRect() ve drawArc() (useCenter=false ile) komutlarıdır. Bu çizim komutlarının diğer örnekleri, yukarıdaki grafikte "Karmaşık" bölümünde yer alır.

Uygulamanız bu eksik özelliklerden veya sınırlamalardan etkileniyorsa setLayerType(View.LAYER_TYPE_SOFTWARE, null) kodunu çağırarak uygulamanızın yalnızca etkilenen bölümü için donanım hızlandırmayı kapatabilirsiniz. Bu şekilde, diğer her yerde donanım hızlandırmadan yararlanmaya devam edebilirsiniz. Uygulamanızda farklı düzeylerde donanım hızlandırmayı etkinleştirme ve devre dışı bırakmayla ilgili daha fazla bilgi için Donanım hızlandırmayı kontrol etme bölümüne bakın.

Katmanları görüntüleme

Android'in tüm sürümlerinde görünümler, görünümün çizim önbelleği veya Canvas.saveLayer() kullanılarak ekran dışı arabellekler halinde oluşturulabiliyordu. Ekran dışı arabelleklerin veya katmanların çeşitli kullanım alanları vardır. Karmaşık görünümleri canlandırırken daha iyi performans elde etmek veya kompozisyon efektleri uygulamak için bunları kullanabilirsiniz. Örneğin, bir görünümü geçici olarak bir katmanda oluşturmak için Canvas.saveLayer() kullanarak şeffaflaştırma efektleri uygulayabilir, ardından bu efekti bir opaklık faktörü ile tekrar ekranda birleştirebilirsiniz.

Android 3.0 (API düzeyi 11) sürümünden itibaren, View.setLayerType() yöntemiyle katmanları nasıl ve ne zaman kullanacağınız konusunda daha fazla kontrole sahip olacaksınız. Bu API iki parametre alır: kullanmak istediğiniz katmanın türü ve katmanın nasıl birleştirilmesi gerektiğini açıklayan isteğe bağlı Paint nesnesi. Bir katmana renk filtreleri, özel karıştırma modları veya opaklık uygulamak için Paint parametresini kullanabilirsiniz. Bir görünümde üç katman türünden biri kullanılabilir:

  • LAYER_TYPE_NONE: Görünüm normal şekilde oluşturulur ve ekran dışı bir arabellek tarafından desteklenmez. Bu, varsayılan davranıştır.
  • LAYER_TYPE_HARDWARE: Uygulama donanım hızlandırmalıysa görünüm donanımda bir donanım dokusu olarak oluşturulur. Uygulama donanım hızlandırmalı değilse bu katman türü LAYER_TYPE_SOFTWARE ile aynı şekilde davranır.
  • LAYER_TYPE_SOFTWARE: Görünüm, yazılımda bit eşlem halinde oluşturulur.

Kullandığınız katman türü hedefinize bağlıdır:

  • Performans: Donanım dokusu görünümü oluşturmak için bir donanım katmanı türü kullanın. Görünüm bir katmanda oluşturulduktan sonra, görünüm invalidate() çağrısı yapana kadar çizim kodunun yürütülmesine gerek yoktur. Alfa animasyonlar gibi bazı animasyonlar, daha sonra doğrudan katmana uygulanabilir. Bu da GPU'nun yapması çok verimlidir.
  • Görsel efektler: Bir görünüme özel görsel işlemler uygulamak için donanım veya yazılım katman türü ve Paint kullanın. Örneğin, ColorMatrixColorFilter kullanarak siyah beyaz bir görünüm çizebilirsiniz.
  • Uyumluluk: Bir görünümü yazılımda oluşturulmaya zorlamak için bir yazılım katmanı türü kullanın. Donanım hızlandırmalı bir görünümde (örneğin, uygulamanızın tamamı donanım hızlandırmalıysa) oluşturma sorunları yaşanıyorsa bu yöntem, donanım oluşturma ardışık düzeninin sınırlamalarını aşmanın kolay bir yoludur.

Katmanları ve animasyonları görüntüleme

Uygulamanız donanım hızlandırmalı olduğunda donanım katmanları daha hızlı ve daha akıcı animasyonlar sunabilir. Çok fazla çizim işlemi gerektiren karmaşık görünümler canlandırılırken animasyonun saniyede 60 kare hızında çalıştırılması her zaman mümkün değildir. Görünümü bir donanım dokusu oluşturmak için donanım katmanları kullanılarak bu durum azaltılabilir. Daha sonra donanım dokusu, görünümü canlandırmak için kullanılabilir. Böylece, animasyonlu hale gelirken görünümün sürekli olarak yeniden çizilmesine gerek kalmaz. Görünümün özelliklerini değiştirmediğiniz (invalidate()) veya invalidate() yöntemini manuel olarak çağırmadığınız sürece görünüm yeniden çizilmez. Uygulamanızda bir animasyon çalıştırıyorsanız ve istediğiniz düzgün sonuçları elde edemiyorsanız animasyonlu görünümlerinizde donanım katmanlarını etkinleştirmeyi düşünün.

Bir görünüm bir donanım katmanıyla desteklendiğinde, bazı özellikleri katmanın ekranda birleştirilme yöntemiyle işlenir. Bu özelliklerin ayarlanması, görünümün geçersiz kılınıp yeniden çizilmesini gerektirmediğinden verimlidir. Aşağıdaki özellikler listesi, katmanın birleştirilme şeklini etkiler. Bu özelliklerden herhangi biri için ayarlayıcının çağrılması, optimum görünümün geçersiz kılınmasına ve hedeflenen görünümün yeniden çizilmemesine neden olur:

  • alpha: Katmanın opaklığını değiştirir
  • x, y, translationX, translationY: Katmanın konumunu değiştirir
  • scaleX, scaleY: Katmanın boyutunu değiştirir
  • rotation, rotationX, rotationY: 3D alanda katmanın yönünü değiştirir
  • pivotX, pivotY: Katmanın dönüşüm kaynağını değiştirir

Bu özellikler, ObjectAnimator ile bir görünüm canlandırılırken kullanılan adlardır. Bu özelliklere erişmek isterseniz ilgili setter veya alıcıyı çağırın. Örneğin, alfa özelliğini değiştirmek için setAlpha() çağrısı yapın. Aşağıdaki kod snippet'i, bir görünümü Y ekseni etrafında 3D olarak döndürmenin en etkili yolunu göstermektedir:

Kotlin

view.setLayerType(View.LAYER_TYPE_HARDWARE, null)
ObjectAnimator.ofFloat(view, "rotationY", 180f).start()

Java

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator.ofFloat(view, "rotationY", 180).start();

Donanım katmanları video belleği kullandığından, bunları yalnızca animasyon süresince etkinleştirmeniz ve animasyon bittikten sonra devre dışı bırakmanız önemle tavsiye edilir. Bunu, animasyon işleyicileri kullanarak yapabilirsiniz:

Kotlin

view.setLayerType(View.LAYER_TYPE_HARDWARE, null)
ObjectAnimator.ofFloat(view, "rotationY", 180f).apply {
    addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            view.setLayerType(View.LAYER_TYPE_NONE, null)
        }
    })
    start()
}

Java

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180);
animator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        view.setLayerType(View.LAYER_TYPE_NONE, null);
    }
});
animator.start();

Tesis animasyonu hakkında daha fazla bilgi için Mülk animasyonu konusuna bakın.

İpuçları ve püf noktaları

Donanım hızlandırmalı 2D grafiğe geçiş yapmak performansı anında artırabilir. Ancak yine de aşağıdaki önerileri uygulayarak uygulamanızı GPU'yu etkili bir şekilde kullanacak şekilde tasarlamanız gerekir:

Başvurunuzun görüntülenme sayısını azaltma
Sistemin çizim yapması ne kadar fazla olursa o kadar yavaş olur. Bu durum, yazılım oluşturma ardışık düzeni için de geçerlidir. Görüntüleme sayısını azaltmak, kullanıcı arayüzünüzü optimize etmenin en kolay yollarından biridir.
Fazla çizim yapmaktan kaçınma
Birbirinin üzerine çok fazla katman çizmeyin. Üzerinde diğer opak görünümler tarafından tamamen gizlenen görünümleri kaldırın. Birbirlerinin üzerine karıştırılmış birkaç katman çizmeniz gerekiyorsa bunları tek bir katmanda birleştirmeyi düşünün. Mevcut donanım için önemli bir kural, her karede ekranda piksel sayısının 2,5 katından (bit eşlem sayısındaki şeffaf pikseller) fazla çizim yapmamaktır.
Çizim yöntemlerinde oluşturma nesneleri oluşturma
Yaygın olarak yapılan bir hata, oluşturma yöntemi her çağrıldığında yeni bir Paint veya yeni bir Path oluşturmaktır. Bu durum, çöp toplayıcıyı daha sık çalışmaya zorlar ve donanım ardışık düzenindeki önbellekleri ve optimizasyonları atlar.
Şekilleri çok sık değiştirmeyin
Örneğin, karmaşık şekiller, yollar ve daireler oluşturmak için doku maskeleri kullanılır. Bir yol oluşturduğunuzda veya değiştirdiğinizde donanım ardışık düzeni, pahalı olabilecek yeni bir maske oluşturur.
Bit eşlemleri çok sık değiştirmeyin
Bir bit eşlemin içeriğini her değiştirdiğinizde, bir sonraki çiziminizde bu içerik tekrar GPU dokusu olarak yüklenir.
Alfa sürümünü dikkatli kullanın
setAlpha(), AlphaAnimation veya ObjectAnimator kullanarak bir görünümü yarı saydam yaptığınızda, gerekli doluluk oranını iki katına çıkaran ekran dışı bir arabellekte oluşturulur. Çok büyük görünümlerde alfa uygularken görünümün katman türünü LAYER_TYPE_HARDWARE olarak ayarlayın.