invalidate() — mi ez, az újrarajzolás mechanizmusa és invalidate(Rect)

Szerző: IT Sectr Megjelenés: 2026-07-20 Olvasási idő: 7 perc

invalidate() — a View osztály metódusa Androidban, amely megjelöli a nézetet, mint újrarajzolást igénylőt. Az invalidate() hívása a nézet újrarajzolásához vezet a legközelebbi képernyőfrissítési ciklusban, így ez a fő mechanizmusa az egyedi komponensek vizuális állapotának frissítésének. Az Android Developers Documentation (2025) szerint az invalidate() az egyedi View-k 90%-ában használatos az adatváltozások és a képernyőn való megjelenítés szinkronizálására. A metódus aszinkron működik — csak beállítja a dirty flag-et és azonnal visszaadja a vezérlést.

Főbb pontok

  • invalidate() — aszinkron újrarajzolási kérés View-hoz Androidban, dirty flag mechanizmuson keresztül működik
  • postInvalidate() — az invalidate() verziója háttérszálból való híváshoz, szálbiztos
  • invalidate(Rect) — részleges újrarajzolás csak a megadott területen a teljesítmény optimalizálásához
  • onDraw() — metódus, amelyet a rendszer az invalidate() után hív meg, analóg a draw(_:) függvénnyel iOS-ben
  • invalidate() vs requestLayout() — invalidate() újrarajzolja a tartalmat, requestLayout() újraszámolja a geometriát

Mi az invalidate() Androidban

invalidate() — az android.view.View osztály metódusa, amely értesíti az Android rendszert, hogy a nézet vizuális megjelenítése elavult. A metódus meghívása után a rendszer megjelöli a nézetet dirty jelzéssel, és ütemezi annak újrarajzolását a legközelebbi képernyőfrissítési ciklusban (általában 16 ms 60 FPS esetén).

Az invalidate() metódus különböző formákat ölthet: paraméter nélkül (teljes újrarajzolás), Rect paraméterrel (részleges) és ltrb paraméterekkel (left, top, right, bottom). Minden verzió aszinkron működik, és az UI szálból hívható. Háttérszálakból való híváshoz létezik a postInvalidate().

Hogyan működik az újrarajzolás az invalidate()-en keresztül

Az újrarajzolás mechanizmusa Androidban a ViewRootImpl -on alapul — egy belső komponensen, amely összeköti a View Hierarchy-t a Surface-szel a rajzoláshoz. Amikor invalidate() kerül meghívásra, a ViewRootImpl megjelöli a nézet területét dirty jelzéssel, és újrarajzolási kérelmet küld a Choreographer -en keresztül — egy rendszerszolgáltatáson, amely szinkronizálja a rajzolást a képernyő frissítési frekvenciájával.

Újrarajzolási ciklus

A Choreographer jelet kap a Vsync-től, és elindít egy hármas áthaladást: measure, layout, draw. Azonban az invalidate() csak a draw fázisra hat — a measure és layout fázisok nem hajtódnak végre, hacsak nem hívták meg a requestLayout()-ot. Ez a kulcsfontosságú különbség: az invalidate() olcsóbb, mint a requestLayout(), mert nem számolja újra a geometriát.

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() // Újrarajzolási kérés
    }

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

        // Grafikonvonal rajzolása
        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)
    }
}

Ebben a példában egy egyedi View grafikon rajzolásához invalidate()-et hív meg az adatok frissítésekor. A rendszer csak ezt a View-t rajzolja újra, anélkül hogy a hierarchia többi elemére hatna. onDraw() megkapja a Canvas-t a vonalak Path-en keresztüli rajzolásához.

invalidate() vs postInvalidate()

A fő különbség az invalidate() és a postInvalidate() között a szálbiztonság. invalidate() csak az UI szálból (fő szálból) hívható. postInvalidate() bármely szálból meghívható — Handleren keresztül küldi az újrarajzolási kérelmet az UI szálba.

Jellemzőinvalidate()postInvalidate()
Hívás szálUI szál (fő szál)Bármely szál
MechanizmusDirty flag közvetlen frissítéseHandler.post() segítségével az UI szálba
KésleltetésMinimális, az aktuális ciklusbanA következő UI szál ciklusig
TeljesítményMagasKis többletterhelés a Handleren
AjánlásUI szálhoz mindig invalidate()Csak háttérszálakhoz

A gyakorlatban a postInvalidate() hálózati adatbetöltés, érzékelőeredmények feldolgozása vagy háttérszámítások esetén használatos. Ha az UI szálban van — mindig invalidate()-et használjon a minimális késleltetésért.

kotlin
    // UI szálból hívva
view.invalidate()

    // Háttérszálból hívva
Thread {
    // Nehéz számítások
    val result = performHeavyCalculation()
    runOnUiThread {
        updateUi(result)
    }
}.start()

Részleges újrarajzolás az invalidate(Rect) segítségével

invalidate(Rect) és invalidate(int l, int t, int r, int b) lehetővé teszi az újrarajzolási terület korlátozását. Ez kritikus a teljesítmény szempontjából: ha csak a View egy részét frissítjük (pl. kurzor mozgatása, jelző megváltoztatása), nincs értelme az egész nézetet újrarajzolni.

A rendszer átadja a megadott dirty téglalapot az onDraw()-nak a canvas.clipBounds segítségével. Az onDraw()-on belül ellenőrizhető a clipBounds, és csak ezen a területen belül lehet rajzolni, bár az Android Canvas automatikusan levágja a rajzolást a dirty téglalapon kívül.

kotlin
    // Részleges frissítés: csak kurzor terület
private val cursorRect = Rect()

fun moveCursorTo(newX: Int, newY: Int) {
    // Régi pozíció érvénytelenítése
    invalidate(cursorRect)

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

    // Új pozíció érvénytelenítése
    invalidate(cursorRect)
}

Részleges újrarajzolás nélkül minden kurzormozgás az egész View-t újrarajzolná, ami egy nagy grafikon esetében több ezer pixel újrarajzolását jelentené néhány tíz helyett. invalidate(Rect) — kötelező technika szerkesztőkhöz, rajzoló vásznakhoz és animált komponensekhez.

invalidate() vs requestLayout(): mi a különbség

Az egyik gyakori hiba, hogy requestLayout()-ot hívnak ott, ahol invalidate() is elég, és fordítva. A különbség alapvető: invalidate() csak a draw fázisra hat, míg a requestLayout() elindítja a teljes measure → layout → draw ciklust.

Szempontinvalidate()requestLayout()
Ciklus fázisaiCsak drawmeasure + layout + draw
Mikor használjukCsak a rajzolás változik (szín, szöveg, grafika)A nézet mérete vagy pozíciója változik
TeljesítményKönnyű — csak újrarajzolásNehéz — hierarchia újraszámolása
Hatás a hierarchiáraCsak az aktuális nézetBefolyásolhatja a szülő tárolókat

Ha szöveget változtat a TextView-ban — elegendő az invalidate(), mivel a nézet mérete nem változik. Ha a szöveg új sorba kerülhet és növelheti a magasságot — requestLayout() szükséges. Android Lint segít az ilyen hibák követésében teljesítményszabályokon keresztül.

Az invalidate() teljesítményének optimalizálása

A túlzott invalidate() hívások — az egyedi View-k alacsony teljesítményének egyik fő oka Androidban. Tekintsük át az optimalizálási technikákat.

Minimalizálja a hívások gyakoriságát

Ha az adatok nagy gyakorisággal frissülnek (érzékelők, animáció, videó), ne hívja meg az invalidate()-et minden változáskor. Használja a ValueAnimator-t vagy a Choreographer.FrameCallback-et a képernyő frissítési frekvenciájával való szinkronizáláshoz. Ez garantálja, hogy az invalidate() nem hívódik meg többször, mint egyszer kockánként.

Használja a Hardware Acceleration-t

Az API 14-től kezdve az Android támogatja a hardveres gyorsítást GPU-n keresztül. Ha az egyedi View csak Canvas API-t (drawRect, drawCircle, drawPath) használ, a gyorsítás átláthatóan működik. DisplayList-kompatibilis műveletekhez az invalidate() jelentősen gyorsabban kerül feldolgozásra.

kotlin
// Choreographer használata Vsync szinkronizáláshoz
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
    updateAnimation(frameTimeNanos)
    invalidate()
    Choreographer.getInstance().postFrameCallback(this)
}

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

Használja az invalidate(Rect)-et pontszerű frissítésekhez, kerülje az invalidate() hívását onDraw()-ból (végtelen ciklus), és mindig profilozzon GPU Profile Rendering segítségével az eszközön. Ez megmutatja az egyes kockák rajzolási idejét, és segít azonosítani a problémás helyeket.

Gyakran Ismételt Kérdések

Hívható invalidate() az onDraw()-ból?

Nem, az invalidate() meghívása az onDraw()-on belül végtelen újrarajzolási ciklust hoz létre: az onDraw() meghívja az invalidate()-et, ami újra elindítja az onDraw()-ot. Ez a CPU 100%-os terheléséhez és kockavesztéshez vezet. Használjon animációkat a ValueAnimator vagy Choreographer segítségével.

Miben különbözik az invalidate() a postInvalidate()-től?

invalidate() csak az UI szálban működik, és azonnal frissíti a dirty flag-et. postInvalidate() a Handleren keresztül küldi a kérelmet az UI szálba, és bármely háttérszálból hívható. Ha az UI szálban van — használja az invalidate()-et a minimális késleltetésért.

A setText() a TextView-ban automatikusan meghívja az invalidate()-et?

Igen, a TextView-n belül a setText() metódus meghívja az invalidate()-et a szöveg frissítése után. Ha a szöveg megváltoztatta a nézet méreteit, kiegészítőleg requestLayout() kerül meghívásra. A fejlesztőnek nem kell manuálisan meghívnia az invalidate()-et a szabványos widgetek használatakor.

Hogyan befolyásolja az invalidate() a teljesítményt 60 FPS-nél?

Minden invalidate() hívás a következő Vsync-ben (16 ms-ként) ütemezi az újrarajzolást. Ha az onDraw() tovább tart 16 ms-nál, kockavesztés következik be. Optimalizálja az onDraw()-ot — gyorsítótárazza a Bitmap-ot, kerülje az allokációkat, és használja a Hardware Acceleration-t a GPU rajzoláshoz.

Meg kell hívni az invalidate()-et a Paint tulajdonságainak megváltoztatása után?

Igen, a Paint tulajdonságainak (szín, vastagság, stílus) megváltoztatása után meg kell hívni az invalidate()-et, mert a View nem követi automatikusan a Paint objektumok változásait. A rendszer nem tudja, hogy a Paint megváltozott, és nem hívja meg az onDraw()-ot explicit kérés nélkül.

Összefoglaló

  • invalidate() — a View újrarajzolásának fő mechanizmusa Androidban, aszinkron működik dirty flag segítségével
  • postInvalidate() — szálbiztos verzió háttérszálakból való híváshoz, Handlert használ
  • invalidate(Rect) — csak a megadott terület részleges újrarajzolása, kritikus a teljesítményhez pontszerű változásoknál
  • requestLayout() — elindítja a teljes measure + layout + draw ciklust, jelentősen nehezebb, mint invalidate()
  • Choreographer — rendszerszolgáltatás a Vsync-kel való szinkronizációhoz, ajánlott az invalidate()-es animációkhoz
  • Hardware Acceleration — GPU gyorsítás elérhető API 14-től, felgyorsítja az invalidate() feldolgozását Canvas API-hoz
  • GPU Profile Rendering — profilozó eszköz a rajzolási idő méréséhez és a lassú onDraw() azonosításához

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is