Ответ
Создание объектов в onDraw() приводит к частым аллокациям памяти, т.к. метод вызывается при каждом перерисовке View (60 раз/сек для 60fps). Это провоцирует GC сборки, что вызывает лаги в UI. Лучше инициализировать объекты заранее (например, в конструкторе View) и переиспользовать их.
Пример плохого кода:
override fun onDraw(canvas: Canvas) {
val paint = Paint() // Создается каждый вызов onDraw
paint.color = Color.RED
canvas.drawCircle(50f, 50f, 25f, paint)
}
Хороший вариант:
private val paint = Paint() // Инициализируется один раз
override fun onDraw(canvas: Canvas) {
paint.color = Color.RED
canvas.drawCircle(50f, 50f, 25f, paint)
} Ответ 18+ 🔞
Эй, слушай сюда, я тебе сейчас такую вещь открою, что ты сам от себя охуеешь. Представь, ты пишешь кастомную вьюху, всё вроде норм, а она лагает, как старая телега по ухабам. И ты сидишь, чешешь репу: "Ёпта, в чём же дело?"
А дело, блядь, в том, что некоторые умники любят в методе onDraw() создавать объекты. Ну, типа, val paint = Paint() прямо там, внутри. И вроде бы логично: нужна кисть — создал, нарисовал, похуй. Но onDraw()-то вызывается, чувак, овердохуища раз! Если у тебя 60 кадров в секунду, то это 60 раз за секунду твой Paint создаётся и... сразу на свалку. А потом приходит сборщик мусора (GC), этот пидарас шерстяной, и начинает свою пляску с бубном, вычищая эту херню. И вот в этот самый момент интерфейс и подтормаживает, потому что главный поток занят не рисованием, а выносом мусора.
Это пиздец как неэффективно. Представь, что ты на кухне. Тебе нужно 60 раз за минуту нарезать хлеб. Плохой способ — каждый раз доставать новый нож из запечатанной упаковки, отрезать один ломтик и выкидывать нож в мусорку. Через минуту у тебя куча мусора, и ты ползаешь по кухне, собирая эти ножи, вместо того чтобы резать хлеб. Хороший способ — достать один нож в начале и резать им все 60 раз.
Вот смотри, как выглядит этот кривой код, от которого у любого нормального разработчика волнение ебать начинается:
override fun onDraw(canvas: Canvas) {
val paint = Paint() // Создается каждый вызов onDraw
paint.color = Color.RED
canvas.drawCircle(50f, 50f, 25f, paint)
}
Видишь эту строку? val paint = Paint(). Это и есть тот самый одноразовый нож. Каждый кадр — новый объект. Каждый кадр — нагрузка на память. Каждый кадр — потенциальный вызов GC. Хуй с горы, да и только.
А теперь смотри, как надо делать, чтобы не было потом мучительно больно:
private val paint = Paint() // Инициализируется один раз
override fun onDraw(canvas: Canvas) {
paint.color = Color.RED
canvas.drawCircle(50f, 50f, 25f, paint)
}
Всё! Кисть paint создаётся один раз, когда создаётся вьюха (или когда лениво инициализируется при первом обращении). А в onDraw() ты её только переиспользуешь. Никаких лишних аллокаций, сборщик мусора спит спокойно, а твой UI летает, как фанера над Парижем. Чих-пых тебя в сраку, вот и вся магия.
Запомни раз и навсегда: onDraw() — священное место для рисования, а не для создания инструментов. Все свои Paint, Path, Rect и прочую требуху готовь заранее. И тогда не придётся гадать, почему анимация дергается, а доверия к твоему коду будет не ноль ебать, а вполне себе положительное.