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

Сколько раз в секунду вызывается метод onDraw() в View?

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

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

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

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

Частота вызова onDraw() и работа системы рендеринга Android

Метод onDraw() вызывается не с фиксированной частотой в секунду, а по необходимости — когда системе требуется перерисовать содержимое View. Частота вызова зависит от множества факторов и определяется системой рендеринга Android, работающей на основе VSync (Vertical Synchronization) сигналов.

Ключевые механизмы, влияющие на вызов onDraw()

  1. Сигналы VSync: В большинстве современных Android-устройств экран обновляется с частотой 60 Гц (реже — 90 Гц, 120 Гц или выше). Это означает, что система получает сигнал VSync каждые ~16.67 мс (при 60 Гц), что задаёт теоретический верхний предел для вызова onDraw() — 60 раз в секунду.

  2. Инвалидация View: onDraw() вызывается только после того, как для View был вызван метод invalidate() (или его варианты, например, postInvalidate()). Без вызова invalidate() перерисовка не произойдёт, даже если придёт сигнал VSync.

  3. Чейнинг рендеринга: Процесс отрисовки состоит из нескольких этапов (measure, layout, draw). Вызов onDraw() происходит на этапе draw. Если контент View не изменился, система может пропустить этап отрисовки для экономии ресурсов.

Практические сценарии частоты вызова

class CustomView(context: Context) : View(context) {
    private var angle = 0f
    
    init {
        // Анимация, которая вызовет invalidate() каждый кадр
        val animator = ValueAnimator.ofFloat(0f, 360f).apply {
            duration = 2000
            repeatCount = ValueAnimator.INFINITE
            addUpdateListener {
                angle = it.animatedValue as Float
                invalidate() // Запрашиваем перерисовку каждый кадр
            }
        }
        animator.start()
    }
    
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // Этот метод будет вызываться с максимальной частотой,
        // которую может поддерживать устройство (обычно 60 раз в секунду)
        canvas.rotate(angle, width / 2f, height / 2f)
        canvas.drawRect(0f, 0f, 100f, 100f, paint)
    }
}

Факторы, ограничивающие частоту вызова

  • Сложность отрисовки: Если onDraw() выполняется дольше 16.67 мс (при 60 Гц), система пропустит кадры (drop frames), и фактическая частота будет ниже.
  • Производительность устройства: На слабых устройствах сложная отрисовка может снизить частоту кадров.
  • Другие процессы в UI-потоке: Если UI-поток занят другими операциями (сеть, вычисления), вызов onDraw() может быть отложен.
  • Тип контента: Статические View вызывают onDraw() редко (только при создании, изменении размера или явной инвалидации). Анимированные View требуют регулярных вызовов.

Как измерить фактическую частоту

class MonitoringView(context: Context) : View(context) {
    private var drawCount = 0
    private var lastLogTime = System.currentTimeMillis()
    
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        drawCount++
        
        val currentTime = System.currentTimeMillis()
        if (currentTime - lastLogTime >= 1000) {
            val fps = drawCount.toFloat() / ((currentTime - lastLogTime) / 1000f)
            Log.d("ViewFPS", "Частота onDraw(): ${"%.1f".format(fps)} раз/сек")
            drawCount = 0
            lastLogTime = currentTime
        }
        
        // Простая отрисовка для теста
        canvas.drawColor(Color.WHITE)
        invalidate() // Постоянно запрашиваем перерисовку
    }
}

Рекомендации для оптимизации

  • Минимизируйте работу в onDraw(): Выносите предварительные вычисления и создание объектов за пределы метода.
  • Используйте аппаратное ускорение: Оно значительно ускоряет отрисовку.
  • Избегайте частых инвалидаций: Не вызывайте invalidate() без необходимости.
  • Для анимаций используйте специальные API: ValueAnimator, ObjectAnimator или Property Animation более эффективны, чем ручной вызов invalidate() в каждом кадре.

Вывод

Метод onDraw() вызывается столько раз в секунду, сколько требуется для отображения актуального контента View, но не чаще частоты обновления экрана устройства. В оптимальных условиях с анимированным контентом на устройстве с 60 Гц экраном — это около 60 раз в секунду. Однако в реальных приложениях частота обычно ниже из-за сложности отрисовки, нагрузки на UI-поток и других факторов. Для плавной анимации необходимо обеспечивать выполнение onDraw() за время меньшее, чем период между сигналами VSync.

Сколько раз в секунду вызывается метод onDraw() в View? | PrepBro