invalidate() — What It Is, Redraw Mechanism and invalidate(Rect)

Author: IT Sectr Published: 2026-07-20 Reading time: 7 min

invalidate() is a method of the View class in Android that marks a view as needing to be redrawn. Calling invalidate() triggers a redraw of the view in the next screen refresh cycle, making it the primary mechanism for updating the visual state of custom components. According to Android Developers Documentation (2025), invalidate() is used in 90% of custom Views to synchronize data changes with on-screen display. The method works asynchronously — it only sets the dirty flag and returns control immediately.

Key Takeaways

  • invalidate() — an asynchronous request to redraw a View in Android, works through the dirty flag mechanism
  • postInvalidate() — a version of invalidate() for calling from a background thread, thread-safe
  • invalidate(Rect) — partial redraw of only the specified area for performance optimization
  • onDraw() — the method called by the system after invalidate(), similar to draw(_:) in iOS
  • invalidate() vs requestLayout() — invalidate() redraws the content, requestLayout() recalculates the geometry

What Is invalidate() in Android

invalidate() is a method of the android.view.View class that tells the Android system that the visual representation of a view is outdated. After calling the method, the system marks the view as dirty and schedules its redraw in the next screen refresh cycle (typically 16 ms for 60 FPS).

The invalidate() method comes in various forms: without parameters (full redraw), with a Rect parameter (partial), and with ltrb parameters (left, top, right, bottom). All versions work asynchronously and must be called from the UI thread. For calling from background threads, there is postInvalidate().

How Redrawing Through invalidate() Works

The redrawing mechanism in Android is based on ViewRootImpl — an internal component that connects the View Hierarchy to the Surface for drawing. When invalidate() is called, ViewRootImpl marks the view area as dirty and sends a redraw request through Choreographer — a system service that synchronizes drawing with the screen refresh rate.

The Redraw Cycle

Choreographer receives a signal from Vsync and initiates a triple pass: measure, layout, draw. However, invalidate() only affects the draw phase — the measure and layout phases are not executed unless requestLayout() was called. This is a key difference: invalidate() is cheaper than requestLayout() because it does not recalculate geometry.

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() // Redraw request
    }

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

        // Drawing chart line
        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 this example, a custom View for drawing a chart calls invalidate() when data is updated. The system only redraws this View without affecting other elements in the hierarchy. onDraw() receives a Canvas for drawing lines through Path.

invalidate() vs postInvalidate()

The main difference between invalidate() and postInvalidate() lies in thread safety. invalidate() must only be called from the UI thread (main thread). postInvalidate() can be called from any thread — it sends a redraw request to the UI thread via Handler.

Characteristicinvalidate()postInvalidate()
Calling ThreadUI thread (main thread)Any thread
MechanismDirect dirty flag updateVia Handler.post() to the UI thread
LatencyMinimal, in the current cycleUntil the next UI thread cycle
PerformanceHighSlight Handler overhead
RecommendationAlways invalidate() for UI threadOnly for background threads

In practice, postInvalidate() is used in scenarios involving network data loading, sensor result processing, or background computations. If you are in the UI thread — always use invalidate() for minimal latency.

kotlin
    // Called from UI thread
view.invalidate()

    // Called from background thread
Thread {
    // Heavy computations
    val result = performHeavyCalculation()
    runOnUiThread {
        updateUi(result)
    }
}.start()

Partial Redraw Through invalidate(Rect)

invalidate(Rect) and invalidate(int l, int t, int r, int b) allow you to limit the redraw area. This is critical for performance: when only part of a View changes (e.g., cursor movement, indicator change), there is no need to redraw the entire view.

The system passes the specified dirty rectangle to onDraw() via canvas.clipBounds. Inside onDraw(), you can check clipBounds and draw only within that area, although Android Canvas automatically clips drawing outside the dirty rectangle.

kotlin
    // Partial update: cursor area only
private val cursorRect = Rect()

fun moveCursorTo(newX: Int, newY: Int) {
    // Invalidate old position
    invalidate(cursorRect)

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

    // Invalidate new position
    invalidate(cursorRect)
}

Without partial redraw, every cursor movement would redraw the entire View, which for a large chart means redrawing thousands of pixels instead of a few dozen. invalidate(Rect) is an essential technique for editors, drawing canvases, and animated components.

invalidate() vs requestLayout(): What’s the Difference

One common mistake is calling requestLayout() where invalidate() would suffice, and vice versa. The difference is fundamental: invalidate() only affects the draw phase, while requestLayout() triggers a full measure → layout → draw cycle.

Aspectinvalidate()requestLayout()
Cycle PhasesDraw onlymeasure + layout + draw
When to UseOnly the rendering changes (color, text, graphics)The size or position of the view changes
PerformanceLightweight — redraw onlyHeavy — recalculates hierarchy
Hierarchy ImpactOnly the current viewMay affect parent containers

If you change text in a TextView, invalidate() is sufficient since the view size does not change. If the text may wrap to a new line and increase the height, requestLayout() is needed. Android Lint helps track such errors through performance rules.

invalidate() Performance Optimization

Excessive invalidate() calls are one of the main causes of poor custom View performance in Android. Let’s look at optimization techniques.

Minimize Call Frequency

If data updates at a high frequency (sensors, animations, video), do not call invalidate() on every change. Use ValueAnimator or Choreographer.FrameCallback to synchronize with the screen refresh rate. This ensures invalidate() is called no more than once per frame.

Use Hardware Acceleration

Since API 14, Android supports hardware acceleration via GPU. If your custom View only uses Canvas API (drawRect, drawCircle, drawPath), acceleration works transparently. For DisplayList-compatible operations, invalidate() is processed significantly faster.

kotlin
// Using Choreographer for Vsync sync
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
    updateAnimation(frameTimeNanos)
    invalidate()
    Choreographer.getInstance().postFrameCallback(this)
}

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

Use invalidate(Rect) for targeted updates, avoid calling invalidate() from onDraw() (infinite loop), and always profile via GPU Profile Rendering on a device. This will show the exact rendering time for each frame and help identify problem areas.

Frequently Asked Questions

Can invalidate() be called from onDraw()?

No, calling invalidate() inside onDraw() creates an infinite redraw loop: onDraw() calls invalidate(), which triggers onDraw() again. This leads to 100% CPU usage and frame drops. Use animations via ValueAnimator or Choreographer.

How is invalidate() different from postInvalidate()?

invalidate() only works in the UI thread and updates the dirty flag immediately. postInvalidate() sends a request via Handler to the UI thread and can be called from any background thread. If you are in the UI thread — use invalidate() for minimal latency.

Does setText() in TextView automatically call invalidate()?

Yes, internally TextView’s setText() calls invalidate() after updating the text. If the text changes the view dimensions, requestLayout() is also called. Developers do not need to manually call invalidate() when working with standard widgets.

How does invalidate() affect performance at 60 FPS?

Each invalidate() call schedules a redraw in the next Vsync (every 16 ms). If onDraw() takes longer than 16 ms, frame drops occur. Optimize onDraw() — cache Bitmaps, avoid allocations, and use Hardware Acceleration for GPU rendering.

Do I need to call invalidate() after changing Paint properties?

Yes, after changing Paint properties (color, thickness, style), you must call invalidate(), because the View does not track Paint object changes automatically. The system does not know the Paint has changed and will not call onDraw() without an explicit request.

Summary

  • invalidate() — the primary mechanism for requesting View redraw in Android, works asynchronously via the dirty flag
  • postInvalidate() — a thread-safe version for calling from background threads, uses Handler
  • invalidate(Rect) — partial redraw of only the specified area, critical for performance with targeted changes
  • requestLayout() — triggers a full measure + layout + draw cycle, significantly more expensive than invalidate()
  • Choreographer — system service for Vsync synchronization, recommended for animations with invalidate()
  • Hardware Acceleration — GPU acceleration available since API 14, speeds up invalidate() handling for Canvas API
  • GPU Profile Rendering — profiling tool for measuring rendering time and identifying slow onDraw() methods

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also