invalidate() — Ce que c'est, mécanisme de redessin et invalidate(Rect)

Auteur : IT Sectr Publié le : 2026-07-20 Temps de lecture : 7 min

invalidate() est une méthode de la classe View dans Android qui marque une vue comme nécessitant un redessin. L'appel à invalidate() déclenche un redessin de la vue dans le prochain cycle de rafraîchissement de l'écran, ce qui en fait le mécanisme principal de mise à jour de l'état visuel des composants personnalisés. Selon la documentation Android Developers (2025), invalidate() est utilisé dans 90 % des vues personnalisées pour synchroniser les changements de données avec l'affichage à l'écran. La méthode fonctionne de manière asynchrone — elle définit simplement le drapeau dirty et retourne immédiatement le contrôle.

Points clés

  • invalidate() — une demande asynchrone de redessin de View dans Android, fonctionne via le mécanisme de drapeau dirty
  • postInvalidate() — version d'invalidate() pour appel depuis un thread d'arrière-plan, thread-safe
  • invalidate(Rect) — redessin partiel uniquement de la zone spécifiée pour l'optimisation des performances
  • onDraw() — la méthode appelée par le système après invalidate(), similaire à draw(_:) dans iOS
  • invalidate() vs requestLayout() — invalidate() redessine le contenu, requestLayout() recalcule la géométrie

Qu'est-ce qu'invalidate() dans Android

invalidate() est une méthode de la classe android.view.View qui informe le système Android que la représentation visuelle d'une vue est obsolète. Après avoir appelé la méthode, le système marque la vue comme dirty et planifie son redessin dans le prochain cycle de rafraîchissement de l'écran (généralement 16 ms pour 60 FPS).

La méthode invalidate() se présente sous différentes formes : sans paramètre (redessin complet), avec un paramètre Rect (partiel) et avec des paramètres ltrb (left, top, right, bottom). Toutes les versions fonctionnent de manière asynchrone et doivent être appelées depuis le thread UI. Pour les appels depuis des threads d'arrière-plan, il existe postInvalidate().

Comment fonctionne le redessin via invalidate()

Le mécanisme de redessin dans Android est basé sur ViewRootImpl — un composant interne qui connecte la hiérarchie des vues à la surface de dessin. Lorsqu'invalidate() est appelé, ViewRootImpl marque la zone de la vue comme dirty et envoie une demande de redessin via Choreographer — un service système qui synchronise le dessin avec la fréquence de rafraîchissement de l'écran.

Le cycle de redessin

Choreographer reçoit un signal de Vsync et lance un triple passage : measure, layout, draw. Cependant, invalidate() n'affecte que la phase draw — les phases measure et layout ne sont pas exécutées à moins que requestLayout() n'ait été appelé. C'est une différence clé : invalidate() est plus léger que requestLayout() car il ne recalcule pas la géométrie.

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() // Demande de redessin
    }

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

        // Dessin de la ligne du graphique
        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)
    }
}

Dans cet exemple, une vue personnalisée pour dessiner un graphique appelle invalidate() lorsque les données sont mises à jour. Le système ne redessine que cette vue sans affecter les autres éléments de la hiérarchie. onDraw() reçoit un Canvas pour dessiner des lignes via Path.

invalidate() vs postInvalidate()

La principale différence entre invalidate() et postInvalidate() réside dans la sécurité des threads. invalidate() ne doit être appelé que depuis le thread UI (thread principal). postInvalidate() peut être appelé depuis n'importe quel thread — il envoie une demande de redessin au thread UI via Handler.

Caractéristiqueinvalidate()postInvalidate()
Thread d'appelThread UI (thread principal)N'importe quel thread
MécanismeMise à jour directe du drapeau dirtyVia Handler.post() vers le thread UI
LatenceMinimale, dans le cycle actuelJusqu'au prochain cycle du thread UI
PerformanceÉlevéeLéger overhead de Handler
RecommandationToujours invalidate() pour le thread UIUniquement pour les threads d'arrière-plan

En pratique, postInvalidate() est utilisé dans des scénarios de chargement de données réseau, de traitement de résultats de capteurs ou de calculs en arrière-plan. Si vous êtes dans le thread UI — utilisez toujours invalidate() pour une latence minimale.

kotlin
    // Appelé depuis le thread UI
view.invalidate()

    // Appelé depuis le thread d'arrière-plan
Thread {
    // Calculs lourds
    val result = performHeavyCalculation()
    runOnUiThread {
        updateUi(result)
    }
}.start()

Redessin partiel via invalidate(Rect)

invalidate(Rect) et invalidate(int l, int t, int r, int b) permettent de limiter la zone de redessin. C'est crucial pour les performances : lorsqu'une seule partie d'une vue change (par exemple, mouvement du curseur, changement d'indicateur), il n'est pas nécessaire de redessiner la vue entière.

Le système transmet le rectangle dirty spécifié à onDraw() via canvas.clipBounds. À l'intérieur d'onDraw(), vous pouvez vérifier clipBounds et dessiner uniquement dans cette zone, bien qu'Android Canvas découpe automatiquement le dessin en dehors du rectangle dirty.

kotlin
    // Mise à jour partielle : zone du curseur uniquement
private val cursorRect = Rect()

fun moveCursorTo(newX: Int, newY: Int) {
    // Invalider l'ancienne position
    invalidate(cursorRect)

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

    // Invalider la nouvelle position
    invalidate(cursorRect)
}

Sans redessin partiel, chaque mouvement du curseur redessinerait la vue entière, ce qui pour un grand graphique signifie redessiner des milliers de pixels au lieu de quelques dizaines. invalidate(Rect) est une technique essentielle pour les éditeurs, les canevas de dessin et les composants animés.

invalidate() vs requestLayout() : quelle est la différence

Une erreur courante est d'appeler requestLayout() là où invalidate() suffirait, et vice versa. La différence est fondamentale : invalidate() n'affecte que la phase draw, tandis que requestLayout() déclenche un cycle complet measure → layout → draw.

Aspectinvalidate()requestLayout()
Phases du cycleDraw uniquementmeasure + layout + draw
Quand l'utiliserSeul le rendu change (couleur, texte, graphiques)La taille ou la position de la vue change
PerformanceLéger — redessin uniquementLourd — recalcule la hiérarchie
Impact sur la hiérarchieUniquement la vue actuellePeut affecter les conteneurs parents

Si vous changez le texte dans un TextView, invalidate() est suffisant car la taille de la vue ne change pas. Si le texte peut passer à une nouvelle ligne et augmenter la hauteur, requestLayout() est nécessaire. Android Lint aide à suivre ces erreurs via des règles de performance.

Optimisation des performances d'invalidate()

Les appels excessifs à invalidate() sont l'une des principales causes de mauvaise performance des vues personnalisées dans Android. Examinons les techniques d'optimisation.

Minimisez la fréquence des appels

Si les données sont mises à jour à haute fréquence (capteurs, animations, vidéo), n'appelez pas invalidate() à chaque changement. Utilisez ValueAnimator ou Choreographer.FrameCallback pour synchroniser avec la fréquence de rafraîchissement de l'écran. Cela garantit qu'invalidate() n'est pas appelé plus d'une fois par image.

Utilisez l'accélération matérielle

Depuis l'API 14, Android prend en charge l'accélération matérielle via GPU. Si votre vue personnalisée utilise uniquement Canvas API (drawRect, drawCircle, drawPath), l'accélération fonctionne de manière transparente. Pour les opérations compatibles avec DisplayList, invalidate() est traité significativement plus rapidement.

kotlin
// Utilisation de Choreographer pour la synchronisation Vsync
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
    updateAnimation(frameTimeNanos)
    invalidate()
    Choreographer.getInstance().postFrameCallback(this)
}

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

Utilisez invalidate(Rect) pour des mises à jour ciblées, évitez d'appeler invalidate() depuis onDraw() (boucle infinie), et profilez toujours via GPU Profile Rendering sur un appareil. Cela montrera le temps de rendu exact de chaque image et aidera à identifier les zones problématiques.

Foire aux questions

Peut-on appeler invalidate() depuis onDraw() ?

Non, appeler invalidate() à l'intérieur d'onDraw() crée une boucle infinie de redessin : onDraw() appelle invalidate(), qui déclenche à nouveau onDraw(). Cela entraîne une utilisation à 100 % du CPU et des chutes d'images. Utilisez des animations via ValueAnimator ou Choreographer.

En quoi invalidate() diffère-t-il de postInvalidate() ?

invalidate() fonctionne uniquement dans le thread UI et met à jour le drapeau dirty immédiatement. postInvalidate() envoie une demande via Handler au thread UI et peut être appelé depuis n'importe quel thread d'arrière-plan. Si vous êtes dans le thread UI — utilisez invalidate() pour une latence minimale.

Est-ce que setText() dans TextView appelle automatiquement invalidate() ?

Oui, en interne, la méthode setText() de TextView appelle invalidate() après la mise à jour du texte. Si le texte modifie les dimensions de la vue, requestLayout() est également appelé. Les développeurs n'ont pas besoin d'appeler manuellement invalidate() lorsqu'ils travaillent avec des widgets standard.

Comment invalidate() affecte-t-il les performances à 60 FPS ?

Chaque appel à invalidate() planifie un redessin dans le prochain Vsync (toutes les 16 ms). Si onDraw() prend plus de 16 ms, des chutes d'images se produisent. Optimisez onDraw() — mettez en cache les Bitmaps, évitez les allocations et utilisez l'accélération matérielle pour le rendu GPU.

Faut-il appeler invalidate() après avoir modifié les propriétés de Paint ?

Oui, après avoir modifié les propriétés de Paint (couleur, épaisseur, style), vous devez appeler invalidate(), car la View ne suit pas automatiquement les modifications des objets Paint. Le système ne sait pas que Paint a changé et n'appellera pas onDraw() sans une demande explicite.

Résumé

  • invalidate() — le mécanisme principal pour demander le redessin de View dans Android, fonctionne de manière asynchrone via le drapeau dirty
  • postInvalidate() — version thread-safe pour l'appel depuis des threads d'arrière-plan, utilise Handler
  • invalidate(Rect) — redessin partiel uniquement de la zone spécifiée, crucial pour les performances avec des modifications ciblées
  • requestLayout() — déclenche un cycle complet measure + layout + draw, significativement plus lourd qu'invalidate()
  • Choreographer — service système pour la synchronisation Vsync, recommandé pour les animations avec invalidate()
  • Hardware Acceleration — accélération GPU disponible depuis l'API 14, accélère le traitement d'invalidate() pour Canvas API
  • GPU Profile Rendering — outil de profilage pour mesurer le temps de rendu et identifier les méthodes onDraw() lentes

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi