invalidate() — is een methode van de klasse View in Android die een weergave markeert als opnieuw getekend moet worden. Het aanroepen van invalidate() leidt tot het hertekenen van de weergave in de dichtstbijzijnde verversingscyclus van het scherm, waardoor het het belangrijkste mechanisme is voor het bijwerken van de visuele status van aangepaste componenten. Volgens Android Developers Documentation (2025) wordt invalidate() gebruikt in 90% van de aangepaste Views om gegevenswijzigingen te synchroniseren met de weergave op het scherm. De methode werkt asynchroon — het stelt alleen de dirty-vlag in en geeft onmiddellijk de controle terug.
Belangrijkste
invalidate() — is een methode van de klasse android.view.View die het Android-systeem informeert dat de visuele weergave van de view verouderd is. Na het aanroepen van de methode markeert het systeem de view als dirty en plant het hertekenen ervan in de dichtstbijzijnde schermverversingscyclus (meestal 16 ms voor 60 FPS).
De methode invalidate() neemt verschillende vormen aan: zonder parameters (volledige hertekening), met de parameter Rect (gedeeltelijk) en met de parameters ltrb (left, top, right, bottom). Alle versies werken asynchroon en kunnen vanuit de UI-thread worden aangeroepen. Voor aanroep vanuit achtergrondthreads bestaat postInvalidate().
Het hertekeningsmechanisme in Android is gebaseerd op ViewRootImpl — een interne component die View Hierarchy verbindt met Surface voor het tekenen. Wanneer invalidate() wordt aangeroepen, markeert ViewRootImpl het gebied van de view als dirty en stuurt een verzoek tot hertekening via Choreographer — een systeemservice die het tekenen synchroniseert met de schermverversingsfrequentie.
Choreographer ontvangt het signaal van Vsync en start een drievoudige doorgang: measure, layout, draw. Echter, invalidate() heeft alleen invloed op de draw-fase — de measure- en layout-fasen worden niet uitgevoerd tenzij requestLayout() is aangeroepen. Dit is het belangrijkste verschil: invalidate() is goedkoper dan requestLayout() omdat het de geometrie niet herberekent.
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() // Hertekeningsverzoek
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.color = Color.BLUE
paint.strokeWidth = 4f
paint.style = Paint.Style.STROKE
// Grafieklijn tekenen
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 dit voorbeeld roept een aangepaste View voor het tekenen van een grafiek invalidate() aan bij het bijwerken van gegevens. Het systeem hertekent alleen deze View, zonder de overige elementen van de hiërarchie te beïnvloeden. onDraw() ontvangt Canvas voor het tekenen van lijnen via Path.
Het belangrijkste verschil tussen invalidate() en postInvalidate() is de threadveiligheid. invalidate() mag alleen vanuit de UI-thread (hoofdthread) worden aangeroepen. postInvalidate() kan vanuit elke thread worden aangeroepen — via Handler stuurt het een hertekeningsverzoek naar de UI-thread.
| Kenmerk | invalidate() | postInvalidate() |
|---|---|---|
| Aanroepthread | UI-thread (hoofdthread) | Elke thread |
| Mechanisme | Directe update van dirty-vlag | Via Handler.post() naar UI-thread |
| Latentie | Minimaal, in huidige cyclus | Tot volgende cyclus van UI-thread |
| Prestatie | Hoog | Kleine overhead op Handler |
| Aanbeveling | Voor UI-thread altijd invalidate() | Alleen voor achtergrondthreads |
In de praktijk wordt postInvalidate() gebruikt in scenario's van het laden van gegevens uit netwerk, verwerking van sensorresultaten of achtergrondberekeningen. Als u zich in de UI-thread bevindt — gebruik dan altijd invalidate() voor minimale latentie.
// Aangeroepen vanuit UI-thread
view.invalidate()
// Aangeroepen vanuit achtergrondthread
Thread {
// Zware berekeningen
val result = performHeavyCalculation()
runOnUiThread {
updateUi(result)
}
}.start()
invalidate(Rect) en invalidate(int l, int t, int r, int b) maken het mogelijk het hertekeningsgebied te beperken. Dit is cruciaal voor prestaties: bij het bijwerken van slechts een deel van View (bijvoorbeeld cursorverplaatsing, indicatorwijziging) heeft het geen zin om de hele view te hertekenen.
Het systeem geeft de opgegeven dirty-rechthoek door aan onDraw() via canvas.clipBounds. Binnen onDraw() kan clipBounds worden gecontroleerd en alleen binnen dit gebied worden getekend, hoewel Android Canvas automatisch het tekenen buiten de dirty-rechthoek begrenst.
// Gedeeltelijke update: alleen cursorgebied
private val cursorRect = Rect()
fun moveCursorTo(newX: Int, newY: Int) {
// Oude positie ongeldig maken
invalidate(cursorRect)
cursorRect.set(newX - 5, newY - 5,
newX + 5, newY + 5)
// Nieuwe positie ongeldig maken
invalidate(cursorRect)
}
Zonder gedeeltelijke hertekening zou elke cursorverplaatsing de hele View hertekenen, wat voor een grote grafiek betekent dat duizenden pixels worden hertekend in plaats van enkele tientallen. invalidate(Rect) — een verplichte techniek voor editors, teken canvassen en geanimeerde componenten.
Een veelgemaakte fout is het aanroepen van requestLayout() waar invalidate() voldoende is, en omgekeerd. Het verschil is fundamenteel: invalidate() heeft alleen invloed op de draw-fase, terwijl requestLayout() de volledige measure → layout → draw-cyclus start.
| Aspect | invalidate() | requestLayout() |
|---|---|---|
| Cyclusfasen | Alleen draw | measure + layout + draw |
| Wanneer gebruiken | Alleen tekening verandert (kleur, tekst, grafiek) | Grootte of positie van view verandert |
| Prestatie | Licht — alleen hertekening | Zwaar — herberekening hiërarchie |
| Invloed op hiërarchie | Alleen huidige view | Kan bovenliggende containers beïnvloeden |
Als u tekst in TextView wijzigt — is invalidate() voldoende, omdat de grootte van de view niet verandert. Als de tekst naar een nieuwe regel kan gaan en de hoogte kan vergroten — is requestLayout() nodig. Android Lint helpt dergelijke fouten te volgen via prestatieregels.
Overmatige invalidate()-aanroepen — een van de belangrijkste oorzaken van lage prestaties van aangepaste Views in Android. Laten we optimalisatietechnieken bekijken.
Als gegevens met hoge frequentie worden bijgewerkt (sensoren, animatie, video), roep dan niet invalidate() aan bij elke wijziging. Gebruik ValueAnimator of Choreographer.FrameCallback voor synchronisatie met de schermverversingsfrequentie. Dit garandeert dat invalidate() niet vaker dan één keer per frame wordt aangeroepen.
Vanaf API 14 ondersteunt Android hardwareversnelling via GPU. Als uw aangepaste View alleen Canvas API (drawRect, drawCircle, drawPath) gebruikt, werkt de versnelling transparant. Voor DisplayList-compatibele bewerkingen wordt invalidate() aanzienlijk sneller verwerkt.
// Choreographer gebruiken voor Vsync-synchronisatie
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
updateAnimation(frameTimeNanos)
invalidate()
Choreographer.getInstance().postFrameCallback(this)
}
fun startAnimation() {
Choreographer.getInstance().postFrameCallback(frameCallback)
}
Gebruik invalidate(Rect) voor puntige updates, vermijd het aanroepen van invalidate() vanuit onDraw() (oneindige lus) en profileer altijd via GPU Profile Rendering op het apparaat. Dit toont de exacte tekentijd van elk frame en helpt problematische plekken te identificeren.
Veelgestelde vragen
Nee, het aanroepen van invalidate() binnen onDraw() creëert een oneindige hertekeningslus: onDraw() roept invalidate() aan, die opnieuw onDraw() start. Dit leidt tot 100% CPU-belasting en frameverlies. Gebruik animaties via ValueAnimator of Choreographer.
invalidate() werkt alleen in de UI-thread en werkt de dirty-vlag onmiddellijk bij. postInvalidate() stuurt een verzoek via Handler naar de UI-thread en kan vanuit elke achtergrondthread worden aangeroepen. Als u in de UI-thread bent — gebruik dan invalidate() voor minimale latentie.
Ja, binnen TextView roept de methode setText() invalidate() aan na het bijwerken van de tekst. Als de tekst de afmetingen van de view heeft gewijzigd, wordt aanvullend requestLayout() aangeroepen. De ontwikkelaar hoeft invalidate() niet handmatig aan te roepen bij het werken met standaard widgets.
Elke invalidate()-aanroep plant hertekening in de volgende Vsync (elke 16 ms). Als onDraw() langer dan 16 ms duurt, vindt frameverlies plaats. Optimaliseer onDraw() — cache Bitmap, vermijd allocaties en gebruik Hardware Acceleration voor GPU-tekening.
Ja, na het wijzigen van Paint-eigenschappen (kleur, dikte, stijl) moet invalidate() worden aangeroepen, omdat View wijzigingen in Paint-objecten niet automatisch volgt. Het systeem weet niet dat Paint is gewijzigd en zal onDraw() niet aanroepen zonder expliciet verzoek.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook