invalidate() — är en metod i klassen View i Android som markerar en vy som i behov av omritning. Anrop av invalidate() leder till omritning av vyn i den närmaste skärmuppdateringscykeln, vilket gör det till den huvudsakliga mekanismen för att uppdatera visuellt tillstånd för anpassade komponenter. Enligt Android Developers Documentation (2025) används invalidate() i 90% av anpassade View för att synkronisera dataändringar med visning på skärmen. Metoden fungerar asynkront — den sätter bara dirty-flaggan och återger omedelbart kontrollen.
Huvudpunkter
invalidate() — är en metod i klassen android.view.View som informerar Android-systemet att den visuella representationen av vyn är föråldrad. Efter metodanropet markerar systemet vyn som dirty och schemalägger dess omritning i den närmaste skärmuppdateringscykeln (vanligtvis 16 ms för 60 FPS).
Metoden invalidate() tar olika former: utan parametrar (fullständig omritning), med parametern Rect (partiell) och med parametrarna ltrb (left, top, right, bottom). Alla versioner fungerar asynkront och kan anropas från UI-tråden. För anrop från bakgrundstrådar finns postInvalidate().
Omritningsmekanismen i Android är baserad på ViewRootImpl — en intern komponent som kopplar View Hierarchy till Surface för ritning. När invalidate() anropas markerar ViewRootImpl vyns område som dirty och skickar en begäran om omritning via Choreographer — en systemtjänst som synkroniserar ritning med skärmuppdateringsfrekvensen.
Choreographer tar emot signal från Vsync och startar en trippel genomgång: measure, layout, draw. Dock påverkar invalidate() endast draw-fasen — measure- och layout-faserna utförs inte om inte requestLayout() har anropats. Detta är den viktigaste skillnaden: invalidate() är billigare än requestLayout() eftersom den inte räknar om geometrin.
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() // Omritningsbegäran
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.color = Color.BLUE
paint.strokeWidth = 4f
paint.style = Paint.Style.STROKE
// Rita graflinje
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)
}
}
I detta exempel anropar en anpassad View för ritning av graf invalidate() vid uppdatering av data. Systemet ritar bara om denna View, utan att påverka övriga element i hierarkin. onDraw() får Canvas för ritning av linjer via Path.
Den huvudsakliga skillnaden mellan invalidate() och postInvalidate() är trådsäkerheten. invalidate() får endast anropas från UI-tråden (huvudtråden). postInvalidate() kan anropas från vilken tråd som helst — via Handler skickar den en begäran om omritning till UI-tråden.
| Egenskap | invalidate() | postInvalidate() |
|---|---|---|
| Anropstråd | UI-tråd (huvudtråd) | Vilken tråd som helst |
| Mekanism | Direkt uppdatering av dirty-flagga | Via Handler.post() till UI-tråden |
| Latens | Minimal, i nuvarande cykel | Till nästa cykel av UI-tråden |
| Prestanda | Hög | Liten overhead på Handler |
| Rekommendation | För UI-tråd alltid invalidate() | Endast för bakgrundstrådar |
I praktiken används postInvalidate() i scenarier med nätverksdataladdning, bearbetning av sensorresultat eller bakgrundsberäkningar. Om du är i UI-tråden — använd alltid invalidate() för minimal latens.
// Anropad från UI-tråd
view.invalidate()
// Anropad från bakgrundstråd
Thread {
// Tunga beräkningar
val result = performHeavyCalculation()
runOnUiThread {
updateUi(result)
}
}.start()
invalidate(Rect) och invalidate(int l, int t, int r, int b) gör det möjligt att begränsa omritningsområdet. Detta är kritiskt för prestanda: vid uppdatering av endast en del av View (t.ex. cursorrörelse, indikatorändring) är det meningslöst att rita om hela vyn.
Systemet skickar den angivna dirty-rektangeln till onDraw() via canvas.clipBounds. Inuti onDraw() kan clipBounds kontrolleras och endast ritas inom detta område, även om Android Canvas automatiskt beskär ritning utanför dirty-rektangeln.
// Partiell uppdatering: endast cursorområde
private val cursorRect = Rect()
fun moveCursorTo(newX: Int, newY: Int) {
// Ogiltigförklara gammal position
invalidate(cursorRect)
cursorRect.set(newX - 5, newY - 5,
newX + 5, newY + 5)
// Ogiltigförklara ny position
invalidate(cursorRect)
}
Utan partiell omritning skulle varje cursorrörelse rita om hela View, vilket för en stor graf innebär omritning av tusentals pixlar istället för några dussin. invalidate(Rect) — en obligatorisk teknik för redigerare, ritdukar och animerade komponenter.
Ett av de vanliga misstagen är att anropa requestLayout() där invalidate() räcker, och tvärtom. Skillnaden är fundamental: invalidate() påverkar endast draw-fasen, medan requestLayout() startar hela measure → layout → draw-cykeln.
| Aspekt | invalidate() | requestLayout() |
|---|---|---|
| Cyklusfaser | Endast draw | measure + layout + draw |
| När använda | Endast ritning ändras (färg, text, grafik) | Storlek eller position på vyn ändras |
| Prestanda | Lätt — endast omritning | Tung — omräkning av hierarki |
| Påverkan på hierarki | Endast aktuell vy | Kan påverka föräldracontainrar |
Om du ändrar text i TextView — räcker invalidate(), eftersom vyns storlek inte ändras. Om texten kan flyttas till en ny rad och öka höjden — behövs requestLayout(). Android Lint hjälper till att spåra sådana fel genom prestandaregler.
Överdrivna invalidate()-anrop — en av de främsta orsakerna till låg prestanda för anpassade View i Android. Låt oss titta på optimeringstekniker.
Om data uppdateras med hög frekvens (sensorer, animation, video), anropa inte invalidate() vid varje ändring. Använd ValueAnimator eller Choreographer.FrameCallback för synkronisering med skärmuppdateringsfrekvensen. Detta garanterar att invalidate() anropas inte mer än en gång per bildruta.
Från API 14 stöder Android hårdvaruacceleration via GPU. Om din anpassade View endast använder Canvas API (drawRect, drawCircle, drawPath), fungerar accelerationen transparent. För DisplayList-kompatibla operationer bearbetas invalidate() betydligt snabbare.
// Använda Choreographer för Vsync-synkronisering
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
updateAnimation(frameTimeNanos)
invalidate()
Choreographer.getInstance().postFrameCallback(this)
}
fun startAnimation() {
Choreographer.getInstance().postFrameCallback(frameCallback)
}
Använd invalidate(Rect) för punktuppdateringar, undvik att anropa invalidate() från onDraw() (oändlig loop) och profilera alltid via GPU Profile Rendering på enheten. Detta visar den exakta ritningstiden för varje bildruta och hjälper att identifiera problematiska områden.
Vanliga frågor
Nej, anrop av invalidate() inuti onDraw() skapar en oändlig omritningsloop: onDraw() anropar invalidate(), som igen startar onDraw(). Detta leder till 100% CPU-belastning och tappade bildrutor. Använd animationer via ValueAnimator eller Choreographer.
invalidate() fungerar endast i UI-tråden och uppdaterar dirty-flaggan omedelbart. postInvalidate() skickar en begäran via Handler till UI-tråden och kan anropas från vilken bakgrundstråd som helst. Om du är i UI-tråden — använd invalidate() för minimal latens.
Ja, inuti TextView anropar metoden setText() invalidate() efter uppdatering av texten. Om texten har ändrat vyns dimensioner, anropas dessutom requestLayout(). Utvecklaren behöver inte manuellt anropa invalidate() vid arbete med standardwidgetar.
Varje invalidate()-anrop schemalägger omritning i nästa Vsync (var 16:e ms). Om onDraw() tar längre än 16 ms, sker tappade bildrutor. Optimera onDraw() — cacha Bitmap, undvik allokeringar och använd Hardware Acceleration för GPU-ritning.
Ja, efter ändring av Paint-egenskaper (färg, tjocklek, stil) måste invalidate() anropas, eftersom View inte automatiskt spårar ändringar i Paint-objekt. Systemet vet inte att Paint har ändrats och kommer inte att anropa onDraw() utan explicit begäran.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också