invalidate(), Android'de View sınıfının bir yöntemidir ve bir görünümü yeniden çizilmesi gereken olarak işaretler. invalidate() çağrısı, sonraki ekran yenileme döngüsünde görünümün yeniden çizilmesini tetikler ve bu da onu özel bileşenlerin görsel durumunu güncellemenin birincil mekanizması haline getirir. Android Developers Documentation'a (2025) göre, invalidate() özel View'lerin %90'ında veri değişikliklerini ekran görüntüsüyle senkronize etmek için kullanılır. Yöntem asenkron olarak çalışır — yalnızca dirty bayrağını ayarlar ve kontrolü hemen geri verir.
Önemli Noktalar
invalidate(), android.view.View sınıfının bir yöntemidir ve Android sistemine bir görünümün görsel temsilinin güncelliğini yitirdiğini bildirir. Yöntem çağrıldıktan sonra sistem, görünümü dirty olarak işaretler ve sonraki ekran yenileme döngüsünde (genellikle 60 FPS için 16 ms) yeniden çizimini planlar.
invalidate() yöntemi çeşitli biçimlerde gelir: parametresiz (tam yeniden çizim), Rect parametreli (kısmi) ve ltrb parametreli (left, top, right, bottom). Tüm sürümler asenkron çalışır ve UI iş parçacığından çağrılmalıdır. Arka plan iş parçacıklarından çağırmak için postInvalidate() bulunur.
Android'de yeniden çizim mekanizması ViewRootImpl'a dayanır — View Hiyerarşisini çizim için Surface'e bağlayan dahili bir bileşen. invalidate() çağrıldığında, ViewRootImpl görünüm alanını dirty olarak işaretler ve Choreographer aracılığıyla bir yeniden çizim isteği gönderir — çizimi ekran yenileme hızıyla senkronize eden bir sistem hizmeti.
Choreographer, Vsync'ten bir sinyal alır ve üç aşamalı bir süreç başlatır: measure, layout, draw. Ancak invalidate() yalnızca draw aşamasını etkiler — requestLayout() çağrılmadıkça measure ve layout aşamaları yürütülmez. Bu önemli bir farktır: invalidate(), geometriyi yeniden hesaplamadığı için requestLayout()'tan daha hafiftir.
class CustomChartView(context: Context, attrs: AttributeSet?)
: View(context, attrs) {
private var dataPoints: List<Float> = emptyList()
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
fun updateData(newPoints: List<Float>) {
dataPoints = newPoints
invalidate() // Yeniden çizim isteği
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.color = Color.BLUE
paint.strokeWidth = 4f
paint.style = Paint.Style.STROKE
// Grafik çizgisi çiziliyor
val path = Path()
dataPoints.forEachIndexed { index, value ->
val x = index * width / max(dataPoints.size - 1, 1)
val y = height - value * height
if (index == 0) path.moveTo(x, y)
else path.lineTo(x, y)
}
canvas.drawPath(path, paint)
}
}
Bu örnekte, bir grafik çizmek için özel bir View, veriler güncellendiğinde invalidate() çağrısı yapar. Sistem, hiyerarşideki diğer öğeleri etkilemeden yalnızca bu View'i yeniden çizer. onDraw(), Path aracılığıyla çizgiler çizmek için bir Canvas alır.
invalidate() ve postInvalidate() arasındaki temel fark, iş parçacığı güvenliğinde yatar. invalidate() yalnızca UI iş parçacığından (ana iş parçacığı) çağrılmalıdır. postInvalidate() herhangi bir iş parçacığından çağrılabilir — Handler aracılığıyla UI iş parçacığına bir yeniden çizim isteği gönderir.
| Özellik | invalidate() | postInvalidate() |
|---|---|---|
| Çağrı İş Parçacığı | UI iş parçacığı (ana iş parçacığı) | Herhangi bir iş parçacığı |
| Mekanizma | Doğrudan dirty bayrak güncellemesi | Handler.post() ile UI iş parçacığına |
| Gecikme | Minimum, mevcut döngüde | Sonraki UI iş parçacığı döngüsüne kadar |
| Performans | Yüksek | Handler'da hafif ek yük |
| Öneri | UI iş parçacığı için her zaman invalidate() | Yalnızca arka plan iş parçacıkları için |
Pratikte, postInvalidate() ağ verisi yükleme, sensör sonuçları işleme veya arka plan hesaplamaları senaryolarında kullanılır. UI iş parçacığındaysanız — minimum gecikme için her zaman invalidate() kullanın.
// UI iş parçacığından çağrıldı
view.invalidate()
// Arka plan iş parçacığından çağrıldı
Thread {
// Ağır hesaplamalar
val result = performHeavyCalculation()
runOnUiThread {
updateUi(result)
}
}.start()
invalidate(Rect) ve invalidate(int l, int t, int r, int b), yeniden çizim alanını sınırlamaya olanak tanır. Bu, performans için kritiktir: Bir View'in yalnızca bir kısmı değiştiğinde (örneğin, imleç hareketi, gösterge değişimi), tüm görünümü yeniden çizmeye gerek yoktur.
Sistem, belirtilen dirty dikdörtgeni onDraw()'a canvas.clipBounds aracılığıyla iletir. onDraw() içinde clipBounds'ı kontrol edebilir ve yalnızca bu alan içinde çizim yapabilirsiniz, ancak Android Canvas, dirty dikdörtgenin dışındaki çizimi otomatik olarak kırpar.
// Kısmi güncelleme: yalnızca imleç alanı
private val cursorRect = Rect()
fun moveCursorTo(newX: Int, newY: Int) {
// Eski konumu geçersiz kıl
invalidate(cursorRect)
cursorRect.set(newX - 5, newY - 5,
newX + 5, newY + 5)
// Yeni konumu geçersiz kıl
invalidate(cursorRect)
}
Kısmi yeniden çizim olmadan, her imleç hareketi tüm View'i yeniden çizerdi ve bu, büyük bir grafik için birkaç düzine yerine binlerce pikselin yeniden çizilmesi anlamına gelir. invalidate(Rect), düzenleyiciler, çizim tuvalleri ve animasyonlu bileşenler için gerekli bir tekniktir.
Yaygın bir hata, invalidate()'in yeterli olacağı yerde requestLayout()'u çağırmak ve bunun tersidir. Fark temeldir: invalidate() yalnızca draw aşamasını etkilerken, requestLayout() tam bir measure → layout → draw döngüsünü tetikler.
| Yön | invalidate() | requestLayout() |
|---|---|---|
| Döngü Aşamaları | Yalnızca draw | measure + layout + draw |
| Ne Zaman Kullanılır | Yalnızca işleme değişir (renk, metin, grafik) | Görünümün boyutu veya konumu değişir |
| Performans | Hafif — yalnızca yeniden çizim | Ağır — hiyerarşiyi yeniden hesaplar |
| Hiyerarşi Etkisi | Yalnızca mevcut View | Üst kapsayıcıları etkileyebilir |
Bir TextView'de metin değiştirirseniz, View boyutu değişmediği için invalidate() yeterlidir. Metin yeni bir satıra geçip yüksekliği artırabiliyorsa, requestLayout() gereklidir. Android Lint, performans kuralları aracılığıyla bu tür hataları izlemeye yardımcı olur.
Aşırı invalidate() çağrıları, Android'de özel View performansının düşük olmasının ana nedenlerinden biridir. Optimizasyon tekniklerine bakalım.
Veriler yüksek frekansta (sensörler, animasyonlar, video) güncelleniyorsa, her değişiklikte invalidate() çağırmayın. Ekran yenileme hızıyla senkronize olmak için ValueAnimator veya Choreographer.FrameCallback kullanın. Bu, invalidate()'in kare başına bir defadan fazla çağrılmamasını sağlar.
API 14'ten itibaren Android, GPU aracılığıyla donanım hızlandırmayı destekler. Özel View'iniz yalnızca Canvas API (drawRect, drawCircle, drawPath) kullanıyorsa, hızlandırma şeffaf bir şekilde çalışır. DisplayList uyumlu işlemler için invalidate() önemli ölçüde daha hızlı işlenir.
// Vsync senkronizasyonu için Choreographer kullanma
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
updateAnimation(frameTimeNanos)
invalidate()
Choreographer.getInstance().postFrameCallback(this)
}
fun startAnimation() {
Choreographer.getInstance().postFrameCallback(frameCallback)
}
Hedeflenen güncellemeler için invalidate(Rect) kullanın, onDraw()'dan invalidate() çağırmaktan kaçının (sonsuz döngü) ve her zaman bir cihazda GPU Profile Rendering ile profil oluşturun. Bu, her karenin tam işleme süresini gösterecek ve sorunlu alanları belirlemeye yardımcı olacaktır.
Sıkça Sorulan Sorular
Hayır, onDraw() içinde invalidate() çağırmak sonsuz bir yeniden çizim döngüsü oluşturur: onDraw() invalidate()'i çağırır, bu da tekrar onDraw()'u tetikler. Bu, %100 CPU kullanımına ve kare düşüşlerine yol açar. ValueAnimator veya Choreographer aracılığıyla animasyonlar kullanın.
invalidate() yalnızca UI iş parçacığında çalışır ve dirty bayrağını hemen günceller. postInvalidate(), Handler aracılığıyla UI iş parçacığına bir istek gönderir ve herhangi bir arka plan iş parçacığından çağrılabilir. UI iş parçacığındaysanız — minimum gecikme için invalidate() kullanın.
Evet, dahili olarak TextView'in setText() yöntemi, metni güncelledikten sonra invalidate() çağırır. Metin görünümün boyutlarını değiştirirse, ayrıca requestLayout() da çağrılır. Standart widget'larla çalışırken geliştiricilerin manuel olarak invalidate() çağırması gerekmez.
Her invalidate() çağrısı, sonraki Vsync'te (her 16 ms'de bir) yeniden çizim planlar. onDraw() 16 ms'den uzun sürerse, kare düşüşleri meydana gelir. onDraw()'ı optimize edin — Bitmap'leri önbelleğe alın, ayırmalardan kaçının ve GPU işlemesi için donanım hızlandırmayı kullanın.
Evet, Paint özelliklerini (renk, kalınlık, stil) değiştirdikten sonra invalidate() çağırmalısınız, çünkü View, Paint nesnelerindeki değişiklikleri otomatik olarak izlemez. Sistem, Paint'in değiştiğini bilmez ve açık bir istek olmadan onDraw()'u çağırmaz.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun