invalidate() — ce este, mecanismul de redesenare și invalidate(Rect)

Autor: IT Sectr Publicat: 2026-07-20 Timp de citire: 7 min

invalidate() — este o metodă a clasei View în Android care marchează vederea ca necesitând redesenare. Apelarea invalidate() duce la redesenarea vederii în cel mai apropiat ciclu de actualizare a ecranului, făcându-l principalul mecanism de actualizare a stării vizuale a componentelor personalizate. Conform Android Developers Documentation (2025), invalidate() este utilizat în 90% din View-urile personalizate pentru sincronizarea modificărilor datelor cu afișarea pe ecran. Metoda funcționează asincron — doar setează un flag dirty și returnează controlul imediat.

Principalele

  • invalidate() — cerere asincronă de redesenare a View în Android, funcționează prin mecanismul dirty flag
  • postInvalidate() — versiunea invalidate() pentru apelarea din firul de fundal, sigură pentru fire
  • invalidate(Rect) — redesenare parțială numai a zonei specificate pentru optimizarea performanței
  • onDraw() — metodă apelată de sistem după invalidate(), analogă cu draw(_:) în iOS
  • invalidate() vs requestLayout() — invalidate() redesenează conținutul, requestLayout() recalculează geometria

Ce este invalidate() în Android

invalidate() — este o metodă a clasei android.view.View care informează sistemul Android că reprezentarea vizuală a vederii este învechită. După apelarea metodei, sistemul marchează vederea ca dirty și programează redesenarea acesteia în cel mai apropiat ciclu de actualizare a ecranului (de obicei 16 ms pentru 60 FPS).

Metoda invalidate() ia diferite forme: fără parametri (redesenare completă), cu parametrul Rect (parțială) și cu parametrii ltrb (left, top, right, bottom). Toate versiunile funcționează asincron și pot fi apelate din firul UI. Pentru apelarea din firele de fundal există postInvalidate().

Cum funcționează redesenarea prin invalidate()

Mecanismul de redesenare în Android se bazează pe ViewRootImpl — o componentă internă care leagă View Hierarchy de Surface pentru desenare. Când este apelat invalidate(), ViewRootImpl marchează zona vederii ca dirty și trimite o cerere de redesenare prin Choreographer — un serviciu de sistem care sincronizează desenarea cu frecvența de actualizare a ecranului.

Ciclul de redesenare

Choreographer primește semnalul de la Vsync și lansează o triplă trecere: measure, layout, draw. Totuși, invalidate() afectează doar faza draw — fazele measure și layout nu sunt executate dacă nu a fost apelat requestLayout(). Aceasta este diferența cheie: invalidate() este mai ieftin decât requestLayout() deoarece nu recalculează geometria.

kotlin
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() // Cerere de redescare
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        paint.color = Color.BLUE
        paint.strokeWidth = 4f
        paint.style = Paint.Style.STROKE

        // Desenarea liniei graficului
        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)
    }
}

În acest exemplu, un View personalizat pentru desenarea graficului apelează invalidate() la actualizarea datelor. Sistemul redesenează doar acest View, fără a afecta celelalte elemente ale ierarhiei. onDraw() primește Canvas pentru desenarea liniilor prin Path.

invalidate() vs postInvalidate()

Diferența principală între invalidate() și postInvalidate() este siguranța pentru fire. invalidate() trebuie apelat numai din firul UI (firul principal). postInvalidate() poate fi apelat din orice fir — prin Handler trimite o cerere de redesenare în firul UI.

Caracteristicăinvalidate()postInvalidate()
Fir de apelareFirul UI (firul principal)Orice fir
MecanismActualizare directă a dirty flagPrin Handler.post() la firul UI
LatențăMinimă, în ciclul curentPână la următorul ciclu al firului UI
PerformanțăRidicatăSupraîncărcare mică pe Handler
RecomandarePentru firul UI întotdeauna invalidate()Numai pentru firele de fundal

În practică, postInvalidate() este utilizat în scenarii de încărcare a datelor din rețea, procesare a rezultatelor senzorilor sau calcule de fundal. Dacă vă aflați în firul UI — utilizați întotdeauna invalidate() pentru o latență minimă.

kotlin
    // Apelat din firul UI
view.invalidate()

    // Apelat din firul de fundal
Thread {
    // Calcule grele
    val result = performHeavyCalculation()
    runOnUiThread {
        updateUi(result)
    }
}.start()

Redesenare parțială prin invalidate(Rect)

invalidate(Rect) și invalidate(int l, int t, int r, int b) permit limitarea zonei de redesenare. Acest lucru este critic pentru performanță: la actualizarea doar a unei părți a View (de exemplu, mișcarea cursorului, schimbarea indicatorului) nu are sens să redesenați întreaga vedere.

Sistemul transmite dreptunghiul dirty specificat în onDraw() prin canvas.clipBounds. În interiorul onDraw() se poate verifica clipBounds și desena doar în limitele acestei zone, deși Android Canvas decupează automat desenarea în afara dreptunghiului dirty.

kotlin
    // Actualizare parțială: doar zona cursorului
private val cursorRect = Rect()

fun moveCursorTo(newX: Int, newY: Int) {
    // Invalidează poziția veche
    invalidate(cursorRect)

    cursorRect.set(newX - 5, newY - 5,
                  newX + 5, newY + 5)

    // Invalidează poziția nouă
    invalidate(cursorRect)
}

Fără redescarea parțială, fiecare mișcare a cursorului ar redesena întregul View, ceea ce pentru un grafic mare înseamnă redescarea a mii de pixeli în loc de câteva zeci. invalidate(Rect) — o tehnică obligatorie pentru editoare, pânze de desenare și componente animate.

invalidate() vs requestLayout(): care este diferența

Una dintre greșelile frecvente este apelarea requestLayout() acolo unde este suficient invalidate() și invers. Diferența este fundamentală: invalidate() afectează doar faza draw, iar requestLayout() lansează ciclul complet measure → layout → draw.

Aspectinvalidate()requestLayout()
Fazele cicluluiDoar drawmeasure + layout + draw
Când să utilizațiSe schimbă doar desenarea (culoare, text, grafică)Se schimbă dimensiunea sau poziția vederii
PerformanțăUșor — doar redescareGreu — recalcularea ierarhiei
Impact asupra ierarhieiDoar vederea curentăPoate afecta containerele părinte

Dacă modificați textul în TextView — este suficient invalidate(), deoarece dimensiunea vederii nu se schimbă. Dacă textul se poate muta pe o nouă linie și crește înălțimea — este necesar requestLayout(). Android Lint ajută la urmărirea unor astfel de erori prin reguli de performanță.

Optimizarea performanței invalidate()

Apelurile excesive de invalidate() — una dintre principalele cauze ale performanței scăzute a View-urilor personalizate în Android. Să examinăm tehnicile de optimizare.

Minimizați frecvența apelurilor

Dacă datele se actualizează cu frecvență ridicată (senzori, animație, video), nu apelați invalidate() la fiecare modificare. Utilizați ValueAnimator sau Choreographer.FrameCallback pentru sincronizarea cu frecvența de actualizare a ecranului. Aceasta garantează că invalidate() este apelat nu mai mult de o dată pe cadru.

Utilizați Hardware Acceleration

Începând cu API 14, Android suportă accelerarea hardware prin GPU. Dacă View-ul dvs. personalizat utilizează doar Canvas API (drawRect, drawCircle, drawPath), accelerarea funcționează transparent. Pentru operațiuni compatibile cu DisplayList, invalidate() este procesat semnificativ mai rapid.

kotlin
// Utilizarea Choreographer pentru sincronizarea Vsync
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
    updateAnimation(frameTimeNanos)
    invalidate()
    Choreographer.getInstance().postFrameCallback(this)
}

fun startAnimation() {
    Choreographer.getInstance().postFrameCallback(frameCallback)
}

Utilizați invalidate(Rect) pentru actualizări punctuale, evitați apelarea invalidate() din onDraw() (buclă infinită) și întotdeauna profilează prin GPU Profile Rendering pe dispozitiv. Aceasta va arăta timpul exact de desenare al fiecărui cadru și va ajuta la identificarea punctelor problematice.

Întrebări frecvente

Se poate apela invalidate() din onDraw()?

Nu, apelarea invalidate() în interiorul onDraw() creează o buclă infinită de redescare: onDraw() apelează invalidate(), care lansează din nou onDraw(). Aceasta duce la încărcarea 100% a CPU și pierderea cadrelor. Utilizați animații prin ValueAnimator sau Choreographer.

Cu ce diferă invalidate() de postInvalidate()?

invalidate() funcționează doar în firul UI și actualizează dirty flag imediat. postInvalidate() trimite o cerere prin Handler în firul UI și poate fi apelat din orice fir de fundal. Dacă sunteți în firul UI — utilizați invalidate() pentru o latență minimă.

SetText() în TextView apelează automat invalidate()?

Da, în interiorul TextView metoda setText() apelează invalidate() după actualizarea textului. Dacă textul a modificat dimensiunile vederii, suplimentar este apelat requestLayout(). Dezvoltatorul nu trebuie să apeleze manual invalidate() când lucrează cu widget-uri standard.

Cum afectează invalidate() performanța la 60 FPS?

Fiecare apel invalidate() programează redescarea în următorul Vsync (la fiecare 16 ms). Dacă onDraw() se execută mai mult de 16 ms, are loc pierderea cadrelor. Optimizați onDraw() — faceți cache Bitmap, evitați alocările și utilizați Hardware Acceleration pentru desenarea GPU.

Trebuie apelat invalidate() după modificarea proprietăților Paint?

Da, după modificarea proprietăților Paint (culoare, grosime, stil) trebuie apelat invalidate(), deoarece View nu urmărește automat modificările obiectelor Paint. Sistemul nu știe că Paint s-a modificat și nu va apela onDraw() fără o cerere explicită.

Rezumat

  • invalidate() — mecanismul principal de cerere de redescare a View în Android, funcționează asincron prin dirty flag
  • postInvalidate() — versiune sigură pentru fire pentru apelarea din firele de fundal, utilizează Handler
  • invalidate(Rect) — redescare parțială numai a zonei specificate, critică pentru performanță la modificări punctuale
  • requestLayout() — lansează ciclul complet measure + layout + draw, semnificativ mai greu decât invalidate()
  • Choreographer — serviciu de sistem de sincronizare cu Vsync, recomandat pentru animații cu invalidate()
  • Hardware Acceleration — accelerare GPU disponibilă de la API 14, accelerează procesarea invalidate() pentru Canvas API
  • GPU Profile Rendering — instrument de profilare pentru măsurarea timpului de desenare și identificarea onDraw()-urilor lente

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și