В каком методе Canvas происходит отрисовка
Что проверяют
Знаете ли вы, где в жизненном цикле View происходит рисование и как устроен путь от invalidate() до кадра на экране. Следом обычно спрашивают, почему нельзя создавать объекты в onDraw и чем invalidate() отличается от requestLayout().
Как отвечать
Рисование кастомного View происходит в onDraw(canvas: Canvas). Сам Canvas ничего не вызывает: это инструмент с методами drawRect, drawCircle, drawPath, drawText, drawBitmap, а стиль задаёт Paint. Полезно показать общий порядок:
onMeasure: вычисление размеров, итог черезsetMeasuredDimension;onLayout: расстановка дочерних элементов уViewGroup;draw(canvas): системный метод, который рисует фон, вызываетonDraw, затемdispatchDrawдля детей иonDrawForegroundдля переднего плана и полос прокрутки. Переопределяют обычноonDraw, а неdraw.
Перерисовку запрашивают через invalidate() с главного потока или postInvalidate() с фонового. Если меняется размер, нужен requestLayout(). onDraw выполняется на главном потоке: при 60 Гц на кадр около 16 мс, при 120 Гц вдвое меньше.
С аппаратным ускорением, которое включено по умолчанию, вызовы Canvas не рисуют пиксели сразу, а записываются в display list (RenderNode), который потом исполняет RenderThread. Для рисования из своего потока есть SurfaceView с lockCanvas() и unlockCanvasAndPost(). В Jetpack Compose роль onDraw играют composable Canvas, Modifier.drawBehind и drawWithContent.
Где спотыкаются
Создают Paint, Path или RectF внутри onDraw. Метод вызывается на каждом кадре, лишние аллокации будят сборщик мусора и дают рывки, Lint прямо предупреждает об этом. Объекты создают заранее, в полях.
Наследуются от ViewGroup и удивляются, что onDraw не вызывается. У ViewGroup по умолчанию выставлен флаг willNotDraw, его снимают через setWillNotDraw(false) или рисуют в dispatchDraw.
Вызывают invalidate() внутри onDraw ради анимации и получают бесконечную перерисовку. Для анимаций есть ValueAnimator: он обновляет значение и вызывает перерисовку только пока анимация идёт.