invalidate() ist eine Methode der View-Klasse in Android, die eine Ansicht als neuzeichnungsbedürftig markiert. Der Aufruf von invalidate() löst eine Neuzeichnung der Ansicht im nächsten Bildschirmaktualisierungszyklus aus und ist somit der primäre Mechanismus zur Aktualisierung des visuellen Zustands benutzerdefinierter Komponenten. Laut Android Developers Documentation (2025) wird invalidate() in 90 % der benutzerdefinierten Views verwendet, um Datenänderungen mit der Bildschirmanzeige zu synchronisieren. Die Methode arbeitet asynchron — sie setzt lediglich das dirty-Flag und gibt sofort die Kontrolle zurück.
Wichtigste Punkte
invalidate() ist eine Methode der Klasse android.view.View, die dem Android-System mitteilt, dass die visuelle Darstellung einer Ansicht veraltet ist. Nach dem Aufruf der Methode markiert das System die Ansicht als dirty und plant ihre Neuzeichnung im nächsten Bildschirmaktualisierungszyklus (normalerweise 16 ms für 60 FPS).
Die Methode invalidate() gibt es in verschiedenen Formen: ohne Parameter (vollständige Neuzeichnung), mit einem Rect-Parameter (teilweise) und mit ltrb-Parametern (left, top, right, bottom). Alle Versionen arbeiten asynchron und müssen vom UI-Thread aus aufgerufen werden. Für Aufrufe aus Hintergrundthreads gibt es postInvalidate().
Der Neuzeichnungsmechanismus in Android basiert auf ViewRootImpl — einer internen Komponente, die die View-Hierarchie mit der Zeichenoberfläche verbindet. Wenn invalidate() aufgerufen wird, markiert ViewRootImpl den Ansichtsbereich als dirty und sendet eine Neuzeichnungsanfrage über Choreographer — einen Systemdienst, der das Zeichnen mit der Bildwiederholfrequenz synchronisiert.
Choreographer empfängt ein Signal von Vsync und startet einen dreifachen Durchlauf: measure, layout, draw. Allerdings betrifft invalidate() nur die draw-Phase — die measure- und layout-Phasen werden nicht ausgeführt, es sei denn, requestLayout() wurde aufgerufen. Dies ist ein entscheidender Unterschied: invalidate() ist günstiger als requestLayout(), da es die Geometrie nicht neu berechnet.
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() // Neuzeichnungsanfrage
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.color = Color.BLUE
paint.strokeWidth = 4f
paint.style = Paint.Style.STROKE
// Diagramm linie zeichnen
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)
}
}
In diesem Beispiel ruft eine benutzerdefinierte Ansicht zum Zeichnen eines Diagramms invalidate() auf, wenn Daten aktualisiert werden. Das System zeichnet nur diese Ansicht neu, ohne andere Elemente in der Hierarchie zu beeinflussen. onDraw() erhält ein Canvas zum Zeichnen von Linien über Path.
Der Hauptunterschied zwischen invalidate() und postInvalidate() liegt in der Threadsicherheit. invalidate() darf nur vom UI-Thread (Hauptthread) aus aufgerufen werden. postInvalidate() kann von jedem Thread aus aufgerufen werden — es sendet eine Neuzeichnungsanfrage über Handler an den UI-Thread.
| Eigenschaft | invalidate() | postInvalidate() |
|---|---|---|
| Aufruf-Thread | UI-Thread (Hauptthread) | Jeder Thread |
| Mechanismus | Direkte dirty-Flag-Aktualisierung | Über Handler.post() an den UI-Thread |
| Latenz | Minimal, im aktuellen Zyklus | Bis zum nächsten UI-Thread-Zyklus |
| Leistung | Hoch | Geringer Handler-Overhead |
| Empfehlung | Immer invalidate() für UI-Thread | Nur für Hintergrundthreads |
In der Praxis wird postInvalidate() in Szenarien wie Netzwerkdatenladung, Sensorergebnisverarbeitung oder Hintergrundberechnungen verwendet. Wenn Sie sich im UI-Thread befinden — verwenden Sie immer invalidate() für minimale Latenz.
// Vom UI-Thread aufgerufen
view.invalidate()
// Vom Hintergrundthread aufgerufen
Thread {
// Schwere Berechnungen
val result = performHeavyCalculation()
runOnUiThread {
updateUi(result)
}
}.start()
invalidate(Rect) und invalidate(int l, int t, int r, int b) ermöglichen es, den Neuzeichnungsbereich zu begrenzen. Dies ist für die Leistung entscheidend: Wenn sich nur ein Teil einer Ansicht ändert (z. B. Cursor-Bewegung, Indikator-Änderung), ist es nicht nötig, die gesamte Ansicht neu zu zeichnen.
Das System übergibt das angegebene dirty-Rechteck an onDraw() über canvas.clipBounds. Innerhalb von onDraw() können Sie clipBounds überprüfen und nur innerhalb dieses Bereichs zeichnen, obwohl Android Canvas das Zeichnen außerhalb des dirty-Rechtecks automatisch beschneidet.
// Teilaktualisierung: nur Cursorbereich
private val cursorRect = Rect()
fun moveCursorTo(newX: Int, newY: Int) {
// Alte Position ungültig machen
invalidate(cursorRect)
cursorRect.set(newX - 5, newY - 5,
newX + 5, newY + 5)
// Neue Position ungültig machen
invalidate(cursorRect)
}
Ohne teilweises Neuzeichnen würde jede Cursor-Bewegung die gesamte Ansicht neu zeichnen, was bei einem großen Diagramm das Neuzeichnen von Tausenden Pixeln statt einigen Dutzend bedeutet. invalidate(Rect) ist eine essentielle Technik für Editoren, Zeichenflächen und animierte Komponenten.
Ein häufiger Fehler ist der Aufruf von requestLayout() dort, wo invalidate() ausreichen würde, und umgekehrt. Der Unterschied ist grundlegend: invalidate() betrifft nur die draw-Phase, während requestLayout() einen vollständigen measure → layout → draw-Zyklus auslöst.
| Aspekt | invalidate() | requestLayout() |
|---|---|---|
| Zyklusphasen | Nur draw | measure + layout + draw |
| Wann verwenden | Nur die Darstellung ändert sich (Farbe, Text, Grafik) | Größe oder Position der Ansicht ändert sich |
| Leistung | Leicht — nur Neuzeichnen | Schwer — Neuberechnung der Hierarchie |
| Auswirkung auf Hierarchie | Nur die aktuelle Ansicht | Kann Elterncontainer beeinflussen |
Wenn Sie Text in einem TextView ändern, ist invalidate() ausreichend, da sich die Größe der Ansicht nicht ändert. Wenn der Text in eine neue Zeile umbrechen und die Höhe vergrößern kann, ist requestLayout() erforderlich. Android Lint hilft, solche Fehler durch Leistungsregeln zu verfolgen.
Übermäßige invalidate()-Aufrufe sind eine der Hauptursachen für schlechte Leistung benutzerdefinierter Views in Android. Betrachten wir Optimierungstechniken.
Wenn Daten mit hoher Frequenz (Sensoren, Animationen, Video) aktualisiert werden, rufen Sie invalidate() nicht bei jeder Änderung auf. Verwenden Sie ValueAnimator oder Choreographer.FrameCallback zur Synchronisation mit der Bildwiederholfrequenz. Dies stellt sicher, dass invalidate() nicht mehr als einmal pro Frame aufgerufen wird.
Seit API 14 unterstützt Android Hardwarebeschleunigung über GPU. Wenn Ihre benutzerdefinierte Ansicht nur Canvas API (drawRect, drawCircle, drawPath) verwendet, funktioniert die Beschleunigung transparent. Für DisplayList-kompatible Operationen wird invalidate() deutlich schneller verarbeitet.
// Choreographer für Vsync-Synchronisation verwenden
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
updateAnimation(frameTimeNanos)
invalidate()
Choreographer.getInstance().postFrameCallback(this)
}
fun startAnimation() {
Choreographer.getInstance().postFrameCallback(frameCallback)
}
Verwenden Sie invalidate(Rect) für gezielte Aktualisierungen, vermeiden Sie den Aufruf von invalidate() aus onDraw() (Endlosschleife), und profilieren Sie immer über GPU Profile Rendering auf einem Gerät. Dies zeigt die genaue Renderzeit jedes Frames und hilft, Problembereiche zu identifizieren.
Häufig gestellte Fragen
Nein, der Aufruf von invalidate() innerhalb von onDraw() erzeugt eine Endlosschleife des Neuzeichnens: onDraw() ruft invalidate() auf, was wiederum onDraw() auslöst. Dies führt zu 100 % CPU-Auslastung und Frame-Einbrüchen. Verwenden Sie Animationen über ValueAnimator oder Choreographer.
invalidate() funktioniert nur im UI-Thread und aktualisiert das dirty-Flag sofort. postInvalidate() sendet eine Anfrage über Handler an den UI-Thread und kann von jedem Hintergrundthread aus aufgerufen werden. Wenn Sie im UI-Thread sind — verwenden Sie invalidate() für minimale Latenz.
Ja, intern ruft die Methode setText() von TextView nach der Textaktualisierung invalidate() auf. Wenn der Text die Abmessungen der Ansicht ändert, wird zusätzlich requestLayout() aufgerufen. Entwickler müssen invalidate() bei der Arbeit mit Standard-Widgets nicht manuell aufrufen.
Jeder invalidate()-Aufruf plant eine Neuzeichnung im nächsten Vsync (alle 16 ms). Wenn onDraw() länger als 16 ms dauert, kommt es zu Frame-Einbrüchen. Optimieren Sie onDraw() — cachen Sie Bitmaps, vermeiden Sie Allokationen und verwenden Sie Hardwarebeschleunigung für GPU-Rendering.
Ja, nach Änderung von Paint-Eigenschaften (Farbe, Dicke, Stil) müssen Sie invalidate() aufrufen, da die View Änderungen an Paint-Objekten nicht automatisch verfolgt. Das System weiß nicht, dass sich Paint geändert hat, und wird onDraw() ohne explizite Anfrage nicht aufrufen.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch