← Назад к вопросам

Что такое Choreographer?

1.7 Middle🔥 142 комментариев
#UI и вёрстка#Производительность и оптимизация

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Choreographer в Android?

Choreographer (постановщик, хореограф) — это критически важный системный компонент в Android, который отвечает за синхронизацию и планирование выполнения операций, напрямую связанных с отрисовкой кадров (рендерингом) пользовательского интерфейса. Его основная задача — обеспечить плавную анимацию и отзывчивый UI, работая в тесной связке с механизмом VSYNC (Vertical Synchronization).

Проще говоря, Choreographer — это «дирижёр», который координирует три ключевых «инструмента» (или этапа отрисовки кадра) в правильном порядке и в строго отведённое время, задаваемое сигналами VSYNC (обычно каждые 16.6 мс для 60 Гц).

Как работает Choreographer? Основной цикл

Choreographer управляет очередью обратных вызовов (callbacks), которые выполняются в рамках каждого кадра. Эти обратные вызовы разделены по приоритетам и типам:

  1. CALLBACK_INPUT: Обработка пользовательского ввода (касания, жесты).
  2. CALLBACK_ANIMATION: Выполнение анимаций (включая ObjectAnimator, Transition и другие).
  3. CALLBACK_TRAVERSAL: Наиболее важный этап — обход (traversal) View-дерева, который включает в себя:
    *   **`measure`** (измерение)
    *   **`layout`** (размещение)
    *   **`draw`** (отрисовка в буфер)

Choreographer ждёт сигнала VSYNC от дисплея. Получив его, он последовательно вызывает все зарегистрированные обратные вызовы в порядке их приоритета.

// Пример: как мы можем "встать в очередь" на выполнение в следующем кадре
val choreographer = Choreographer.getInstance()

choreographer.postFrameCallback(object : Choreographer.FrameCallback {
    override fun doFrame(frameTimeNanos: Long) {
        // Этот метод будет вызван в начале следующего кадра,
        // до этапов анимации и обхода (traversal).
        // frameTimeNanos — метка времени, когда должен начаться этот кадр.

        // Выполняем какую-то работу, связанную с UI...
        updateCustomAnimation(frameTimeNanos)

        // При необходимости запрашиваем следующий кадр.
        choreographer.postFrameCallback(this)
    }
})

Для чего используется Choreographer разработчиками?

  • Синхронизация с отрисовкой кадра: Позволяет выполнить код непосредственно перед началом или после завершения рендеринга кадра. Это ключ к созданию плавных анимаций на Canvas или через ValueAnimator с ручным управлением.
  • Измерение производительности: Многие инструменты профилирования (например, Jetpack Macrobenchmark) используют FrameCallback для точного замера времени рендеринга кадра и вычисления показателя пропущенных кадров (jank).
  • Оптимизация «тяжёлых» операций: Позволяет отложить некритичную работу (например, логирование, не срочные вычисления) на момент после CALLBACK_TRAVERSAL, чтобы не мешать отрисовке UI.

Взаимосвязь с другими компонентами

  • ViewRootImpl: Именно этот объект регистрирует TraversalRunnable как CALLBACK_TRAVERSAL в Choreographer. Когда наступает его очередь, запускается performTraversals().
  • Handler и Looper: Choreographer использует основной Looper приложения для планирования своих сообщений. Он представляет собой более высокоуровневую абстракцию, специализированную именно для синхронизации с отрисовкой.
  • RenderThread: На этапе draw команды рендеринга отправляются в отдельный RenderThread, который работает асинхронно. Choreographer помогает скоординировать работу основного потока и RenderThread.

Практический пример: отслеживание FPS (кадров в секунду)

class FpsTracker(private val choreographer: Choreographer = Choreographer.getInstance()) {
    private var frameCount = 0
    private var lastFrameTimeNanos = 0L
    private val frameCallback = object : Choreographer.FrameCallback {
        override fun doFrame(frameTimeNanos: Long) {
            frameCount++
            if (lastFrameTimeNanos > 0) {
                val elapsedSeconds = (frameTimeNanos - lastFrameTimeNanos) / 1_000_000_000.0
                if (elapsedSeconds >= 1.0) {
                    val fps = frameCount / elapsedSeconds
                    Log.d("FpsTracker", "Current FPS: ${"%.1f".format(fps)}")
                    frameCount = 0
                    lastFrameTimeNanos = frameTimeNanos
                }
            } else {
                lastFrameTimeNanos = frameTimeNanos
            }
            choreographer.postFrameCallback(this) // Регистрируемся на следующий кадр
        }
    }

    fun start() {
        choreographer.postFrameCallback(frameCallback)
    }

    fun stop() {
        choreographer.removeFrameCallback(frameCallback)
    }
}

Почему это важно для Android-разработчика?

Понимание работы Choreographer — основа для:

  1. Борьбы с лагами и «тормозами» в интерфейсе. Если работа в основном потоке (особенно в CALLBACK_ANIMATION или CALLBACK_TRAVERSAL) превышает 16 мс, Choreographer не успевает подготовить кадр к следующему VSYNC, и кадр «пропускается» (jank).
  2. Создания сложных кастомных анимаций, которые требуют точного контроля над временем.
  3. Написания эффективного и отзывчивого кода, который уважает цикл отрисовки UI.

Таким образом, Choreographer — это не просто внутренний системный механизм, а центральный узел, определяющий плавность работы любого Android-приложения. Глубокое понимание его принципов позволяет разработчику осознанно управлять рендерингом и создавать продукты с безупречным пользовательским опытом.

Что такое Choreographer? | PrepBro