Сколько раз в секунду вызывается метод onDraw() в View?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Частота вызова onDraw() и работа системы рендеринга Android
Метод onDraw() вызывается не с фиксированной частотой в секунду, а по необходимости — когда системе требуется перерисовать содержимое View. Частота вызова зависит от множества факторов и определяется системой рендеринга Android, работающей на основе VSync (Vertical Synchronization) сигналов.
Ключевые механизмы, влияющие на вызов onDraw()
-
Сигналы VSync: В большинстве современных Android-устройств экран обновляется с частотой 60 Гц (реже — 90 Гц, 120 Гц или выше). Это означает, что система получает сигнал VSync каждые ~16.67 мс (при 60 Гц), что задаёт теоретический верхний предел для вызова
onDraw()— 60 раз в секунду. -
Инвалидация View:
onDraw()вызывается только после того, как для View был вызван методinvalidate()(или его варианты, например,postInvalidate()). Без вызоваinvalidate()перерисовка не произойдёт, даже если придёт сигнал VSync. -
Чейнинг рендеринга: Процесс отрисовки состоит из нескольких этапов (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.