Что делает метод invalidate
Что проверяют
Понимаете ли вы, как View попадает на экран: invalidate() не рисует сразу, а просит перерисовку на следующем кадре. Следом почти всегда спрашивают, чем он отличается от requestLayout() и что вызывать из фонового потока.
Как отвечать
invalidate() помечает View как «грязную» и планирует проход отрисовки. onDraw() вызовется не синхронно, а когда Choreographer получит сигнал vsync и начнётся следующий кадр. Поэтому несколько вызовов в пределах одного кадра схлопываются в одну перерисовку, группировать их вручную не нужно.
- только отрисовка:
measureиlayoutне запускаются. Поменялся размер или положение, нуженrequestLayout(); поменялось и то и другое, вызывают оба; - поток: метод рассчитан на UI-поток. Из фонового есть
postInvalidate(), для анимацийpostInvalidateOnAnimation(), привязанный к кадрам; - аппаратное ускорение: включено по умолчанию, и
invalidate()перезаписывает список команд отрисовки (RenderNode) только этой View, родители заново не рисуются. Варианты с прямоугольникомinvalidate(Rect)устарели в API 28, область система считает сама; - свойства без перерисовки:
setAlpha(),setTranslationX(),setScaleX()меняют свойстваRenderNodeи не вызываютonDraw(), для анимаций это дешевле; - когда не сработает: View не в состоянии
VISIBLEили ещё не прикреплённая к окну перерисовку пропускает.
Типичный сценарий: кастомная View с графиком, сеттер сохраняет данные и зовёт invalidate(). В Jetpack Compose метод руками не вызывают: чтение State внутри drawBehind или Canvas само инвалидирует только фазу рисования.
Где спотыкаются
Ждут, что после invalidate() поменяется размер View. Не поменяется: содержимое перерисуется в старых границах.
Вызывают invalidate() внутри onDraw() без условия. Получается перерисовка каждый кадр, которая ест батарею даже на статичном экране.
Создают Paint, Path, RectF прямо в onDraw(). Вместе с частыми инвалидациями это сотни аллокаций в секунду и паузы GC, из-за которых теряются кадры. Такие объекты создают один раз.