invalidate() — що це, механізм перемалювання та invalidate(Rect)

Автор: IT Sectr Опубліковано: 2026-07-20 Час читання: 7 хв

invalidate() — це метод класу View в Android, який позначає в’ю як таку, що потребує повторного відтворення. Виклик invalidate() призводить до перемалювання в’ю в найближчому циклі оновлення екрана, що робить його основним механізмом оновлення візуального стану кастомних компонентів. За даними Android Developers Documentation (2025), invalidate() використовується в 90% кастомних View для синхронізації змін даних з відображенням на екрані. Метод працює асинхронно — він лише встановлює прапор dirty і повертає керування негайно.

Головне

  • invalidate() — асинхронний запит перемалювання View в Android, працює через dirty flag механізм
  • postInvalidate() — версія invalidate() для виклику з фонового потоку, потокобезпечна
  • invalidate(Rect) — часткове перемалювання лише зазначеної області для оптимізації продуктивності
  • onDraw() — метод, який викликається системою після invalidate(), аналогічний draw(_:) в iOS
  • invalidate() vs requestLayout() — invalidate() перемальовує вміст, requestLayout() перераховує геометрію

Що таке invalidate() в Android

invalidate() — це метод класу android.view.View, який повідомляє системі Android, що візуальне представлення в’ю застаріло. Після виклику методу система позначає в’ю як dirty і планує її перемалювання в найближчому циклі оновлення екрана (зазвичай 16 мс для 60 FPS).

Метод invalidate() приймає різні форми: без параметрів (повне перемалювання), з параметром Rect (часткове) та з параметрами ltrb (left, top, right, bottom). Всі версії працюють асинхронно і можуть викликатися з UI-потоку. Для виклику з фонових потоків існує postInvalidate().

Як працює перемалювання через invalidate()

Механізм перемалювання в Android заснований на ViewRootImpl — внутрішньому компоненті, який пов’язує View Hierarchy з Surface для відтворення. Коли викликається invalidate(), ViewRootImpl позначає область в’ю як dirty і надсилає запит на перемалювання через Choreographer — системний сервіс, який синхронізує відтворення з частотою оновлення екрана.

Цикл перемалювання

Choreographer отримує сигнал від Vsync і запускає потрійний прохід: measure, layout, draw. Однак invalidate() зачіпає лише фазу draw — фази measure і layout не виконуються, якщо не був викликаний requestLayout(). Це ключова відмінність: invalidate() дешевший за requestLayout(), оскільки не перераховує геометрію.

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() // Запит перемалювання
    }

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

        // Малювання лінії графіка
        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)
    }
}

У цьому прикладі кастомний View для відтворення графіка викликає invalidate() при оновленні даних. Система перемальовує лише цей View, не зачіпаючи інші елементи ієрархії. onDraw() отримує Canvas для відтворення ліній через Path.

invalidate() vs postInvalidate()

Основна відмінність між invalidate() та postInvalidate() — у потоковій безпеці. invalidate() повинен викликатися лише з UI-потоку (main thread). postInvalidate() можна викликати з будь-якого потоку — через Handler він надсилає запит на перемалювання в UI-потік.

Характеристикаinvalidate()postInvalidate()
Потік викликуUI-потік (main thread)Будь-який потік
МеханізмПряме оновлення dirty flagЧерез Handler.post() до UI-потоку
LatencyМінімальна, в поточному цикліДо наступного циклу UI-потоку
ПродуктивністьВисокаНевеликий overhead на Handler
РекомендаціяДля UI-потоку завжди invalidate()Лише для фонових потоків

На практиці postInvalidate() використовується в сценаріях завантаження даних з мережі, обробки результатів сенсорів або фонових обчислень. Якщо ви знаходитесь в UI-потоці — завжди використовуйте invalidate() для мінімальної затримки.

kotlin
    // Викликано з UI потоку
view.invalidate()

    // Викликано з фонового потоку
Thread {
    // Важкі обчислення
    val result = performHeavyCalculation()
    runOnUiThread {
        updateUi(result)
    }
}.start()

Часткове перемалювання через invalidate(Rect)

invalidate(Rect) та invalidate(int l, int t, int r, int b) дозволяють обмежити область перемалювання. Це критично важливо для продуктивності: при оновленні лише частини View (наприклад, рух курсора, зміна індикатора) немає сенсу перемальовувати всю в’ю цілком.

Система передає зазначений dirty-прямокутник в onDraw() через canvas.clipBounds. Всередині onDraw() можна перевірити clipBounds і малювати лише в межах цієї області, хоча Android Canvas автоматично кліпує відтворення за межами dirty-прямокутника.

kotlin
    // Часткове оновлення: лише область курсора
private val cursorRect = Rect()

fun moveCursorTo(newX: Int, newY: Int) {
    // Інвалідувати стару позицію
    invalidate(cursorRect)

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

    // Інвалідувати нову позицію
    invalidate(cursorRect)
}

Без часткового перемалювання кожен рух курсора перемальовував би весь View, що для великого графіка означає перемалювання тисяч пікселів замість кількох десятків. invalidate(Rect) — обов’язкова техніка для редакторів, канвасів малювання та анімованих компонентів.

invalidate() vs requestLayout(): в чому різниця

Одна з частих помилок — виклик requestLayout() там, де достатньо invalidate(), і навпаки. Різниця фундаментальна: invalidate() зачіпає лише фазу draw, а requestLayout() запускає повний цикл measure → layout → draw.

Аспектinvalidate()requestLayout()
Фази циклуЛише drawmeasure + layout + draw
Коли використовуватиЗмінюється лише відтворення (колір, текст, графіка)Змінюється розмір або положення в’ю
ПродуктивністьЛегкий — лише перемалюванняВажкий — перерахунок ієрархії
Вплив на ієрархіюЛише поточна в’юМоже зачепити батьківські контейнери

Якщо ви змінюєте текст у TextView — достатньо invalidate(), оскільки розмір в’ю не змінюється. Якщо текст може перенестися на новий рядок і збільшити висоту — потрібен requestLayout(). Android Lint допомагає відстежувати такі помилки через правила продуктивності.

Оптимізація продуктивності invalidate()

Надмірні виклики invalidate() — одна з головних причин низької продуктивності кастомних View в Android. Розглянемо техніки оптимізації.

Мінімізуйте частоту викликів

Якщо дані оновлюються з високою частотою (сенсори, анімація, відео), не викликайте invalidate() на кожну зміну. Використовуйте ValueAnimator або Choreographer.FrameCallback для синхронізації з частотою оновлення екрана. Це гарантує, що invalidate() викликається не частіше одного разу за кадр.

Використовуйте Hardware Acceleration

З API 14 Android підтримує апаратне прискорення через GPU. Якщо ваша кастомна View використовує лише Canvas API (drawRect, drawCircle, drawPath), прискорення працює прозоро. Для DisplayList-сумісних операцій invalidate() обробляється значно швидше.

kotlin
// Використання Choreographer для синхронізації Vsync
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
    updateAnimation(frameTimeNanos)
    invalidate()
    Choreographer.getInstance().postFrameCallback(this)
}

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

Використовуйте invalidate(Rect) для точкових оновлень, уникайте виклику invalidate() з onDraw() (нескінченний цикл), і завжди профілюйте через GPU Profile Rendering на пристрої. Це покаже точний час відтворення кожного кадру та допоможе виявити проблемні місця.

Поширені запитання

Чи можна викликати invalidate() з onDraw()?

Ні, виклик invalidate() всередині onDraw() створює нескінченний цикл перемалювання: onDraw() викликає invalidate(), який знову запускає onDraw(). Це призводить до 100% завантаження CPU та дропу кадрів. Використовуйте анімації через ValueAnimator або Choreographer.

Чим invalidate() відрізняється від postInvalidate()?

invalidate() працює лише в UI-потоці та оновлює dirty flag негайно. postInvalidate() надсилає запит через Handler в UI-потік і може викликатися з будь-якого фонового потоку. Якщо ви в UI-потоці — використовуйте invalidate() для мінімальної затримки.

Чи викликає setText() у TextView автоматичний invalidate()?

Так, всередині TextView метод setText() викликає invalidate() після оновлення тексту. Якщо текст змінив розміри в’ю, додатково викликається requestLayout(). Розробнику не потрібно вручну викликати invalidate() при роботі зі стандартними віджетами.

Як invalidate() впливає на продуктивність при 60 FPS?

Кожен виклик invalidate() планує перемалювання в наступному Vsync (кожні 16 мс). Якщо onDraw() виконується довше 16 мс, відбувається дроп кадрів. Оптимізуйте onDraw() — кешуйте Bitmap, уникайте алокацій та використовуйте Hardware Acceleration для GPU-відтворення.

Чи потрібно викликати invalidate() після зміни властивостей Paint?

Так, після зміни властивостей Paint (колір, товщина, стиль) необхідно викликати invalidate(), оскільки View не відстежує зміни об’єктів Paint автоматично. Система не знає, що Paint змінився, і не викличе onDraw() без явного запиту.

Підсумки

  • invalidate() — основний механізм запиту перемалювання View в Android, працює асинхронно через dirty flag
  • postInvalidate() — потокобезпечна версія для виклику з фонових потоків, використовує Handler
  • invalidate(Rect) — часткове перемалювання лише зазначеної області, критичне для продуктивності при точкових змінах
  • requestLayout() — запускає повний цикл measure + layout + draw, значно важчий ніж invalidate()
  • Choreographer — системний сервіс синхронізації з Vsync, рекомендується для анімацій з invalidate()
  • Hardware Acceleration — GPU-прискорення доступне з API 14, прискорює обробку invalidate() для Canvas API
  • GPU Profile Rendering — інструмент профілювання для вимірювання часу відтворення та виявлення повільних onDraw()

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також