invalidate() é um método da classe View no Android que marca uma view como precisando ser redesenhada. Chamar invalidate() desencadeia um redesenho da view no próximo ciclo de atualização da tela, tornando-o o principal mecanismo para atualizar o estado visual de componentes personalizados. Segundo a documentação do Android Developers (2025), invalidate() é usado em 90% das Views personalizadas para sincronizar alterações de dados com a exibição na tela. O método funciona de forma assíncrona — ele apenas define a flag dirty e retorna o controle imediatamente.
Principais pontos
invalidate() é um método da classe android.view.View que informa ao sistema Android que a representação visual de uma view está desatualizada. Após chamar o método, o sistema marca a view como dirty e agenda seu redesenho no próximo ciclo de atualização da tela (normalmente 16 ms para 60 FPS).
O método invalidate() vem em várias formas: sem parâmetros (redesenho completo), com um parâmetro Rect (parcial) e com parâmetros ltrb (left, top, right, bottom). Todas as versões funcionam de forma assíncrona e devem ser chamadas da thread de UI. Para chamadas de threads em segundo plano, existe postInvalidate().
O mecanismo de redesenho no Android é baseado em ViewRootImpl — um componente interno que conecta a hierarquia de views à superfície de desenho. Quando invalidate() é chamado, ViewRootImpl marca a área da view como dirty e envia uma solicitação de redesenho através de Choreographer — um serviço do sistema que sincroniza o desenho com a taxa de atualização da tela.
Choreographer recebe um sinal de Vsync e inicia uma tripla passagem: measure, layout, draw. No entanto, invalidate() afeta apenas a fase draw — as fases measure e layout não são executadas a menos que requestLayout() tenha sido chamado. Esta é uma diferença chave: invalidate() é mais leve que requestLayout() porque não recalcula a geometria.
class CustomChartView(context: Context, attrs: AttributeSet?)
: View(context, attrs) {
private var dataPoints: List<Float> = emptyList()
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
fun updateData(newPoints: List<Float>) {
dataPoints = newPoints
invalidate() // Solicitação de redesenho
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.color = Color.BLUE
paint.strokeWidth = 4f
paint.style = Paint.Style.STROKE
// Desenhando linha do gráfico
val path = Path()
dataPoints.forEachIndexed { index, value ->
val x = index * width / max(dataPoints.size - 1, 1)
val y = height - value * height
if (index == 0) path.moveTo(x, y)
else path.lineTo(x, y)
}
canvas.drawPath(path, paint)
}
}
Neste exemplo, uma View personalizada para desenhar um gráfico chama invalidate() quando os dados são atualizados. O sistema apenas redesenha esta View sem afetar outros elementos na hierarquia. onDraw() recebe um Canvas para desenhar linhas através de Path.
A principal diferença entre invalidate() e postInvalidate() está na segurança de threads. invalidate() deve ser chamado apenas da thread de UI (thread principal). postInvalidate() pode ser chamado de qualquer thread — ele envia uma solicitação de redesenho para a thread de UI através de Handler.
| Característica | invalidate() | postInvalidate() |
|---|---|---|
| Thread de chamada | Thread de UI (thread principal) | Qualquer thread |
| Mecanismo | Atualização direta da flag dirty | Via Handler.post() para a thread de UI |
| Latência | Mínima, no ciclo atual | Até o próximo ciclo da thread de UI |
| Desempenho | Alto | Pequena sobrecarga do Handler |
| Recomendação | Sempre invalidate() para a thread de UI | Apenas para threads em segundo plano |
Na prática, postInvalidate() é usado em cenários de carregamento de dados de rede, processamento de resultados de sensores ou cálculos em segundo plano. Se você está na thread de UI — use sempre invalidate() para latência mínima.
// Chamado da thread de UI
view.invalidate()
// Chamado da thread em segundo plano
Thread {
// Cálculos pesados
val result = performHeavyCalculation()
runOnUiThread {
updateUi(result)
}
}.start()
invalidate(Rect) e invalidate(int l, int t, int r, int b) permitem limitar a área de redesenho. Isso é crítico para o desempenho: quando apenas parte de uma View muda (por exemplo, movimento do cursor, alteração de indicador), não há necessidade de redesenhar a view inteira.
O sistema passa o retângulo dirty especificado para onDraw() através de canvas.clipBounds. Dentro de onDraw(), você pode verificar clipBounds e desenhar apenas dentro dessa área, embora o Android Canvas recorte automaticamente o desenho fora do retângulo dirty.
// Atualização parcial: apenas área do cursor
private val cursorRect = Rect()
fun moveCursorTo(newX: Int, newY: Int) {
// Invalidar posição antiga
invalidate(cursorRect)
cursorRect.set(newX - 5, newY - 5,
newX + 5, newY + 5)
// Invalidar nova posição
invalidate(cursorRect)
}
Sem redesenho parcial, cada movimento do cursor redesenhearia a View inteira, o que para um gráfico grande significa redesenhar milhares de pixels em vez de algumas dezenas. invalidate(Rect) é uma técnica essencial para editores, canvases de desenho e componentes animados.
Um erro comum é chamar requestLayout() onde invalidate() seria suficiente, e vice-versa. A diferença é fundamental: invalidate() afeta apenas a fase draw, enquanto requestLayout() desencadeia um ciclo completo measure → layout → draw.
| Aspecto | invalidate() | requestLayout() |
|---|---|---|
| Fases do ciclo | Apenas draw | measure + layout + draw |
| Quando usar | Apenas a renderização muda (cor, texto, gráficos) | O tamanho ou posição da view muda |
| Desempenho | Leve — apenas redesenho | Pesado — recalcula a hierarquia |
| Impacto na hierarquia | Apenas a view atual | Pode afetar contêineres pai |
Se você alterar o texto em um TextView, invalidate() é suficiente, pois o tamanho da view não muda. Se o texto pode quebrar em uma nova linha e aumentar a altura, requestLayout() é necessário. Android Lint ajuda a rastrear esses erros através de regras de desempenho.
Chamadas excessivas a invalidate() são uma das principais causas de baixo desempenho em Views personalizadas no Android. Vamos ver as técnicas de otimização.
Se os dados são atualizados com alta frequência (sensores, animações, vídeo), não chame invalidate() em cada alteração. Use ValueAnimator ou Choreographer.FrameCallback para sincronizar com a taxa de atualização da tela. Isso garante que invalidate() seja chamado no máximo uma vez por quadro.
Desde a API 14, o Android suporta aceleração de hardware via GPU. Se sua View personalizada usa apenas Canvas API (drawRect, drawCircle, drawPath), a aceleração funciona de forma transparente. Para operações compatíveis com DisplayList, invalidate() é processado significativamente mais rápido.
// Usando Choreographer para sincronização Vsync
private val frameCallback = Choreographer.FrameCallback { frameTimeNanos ->
updateAnimation(frameTimeNanos)
invalidate()
Choreographer.getInstance().postFrameCallback(this)
}
fun startAnimation() {
Choreographer.getInstance().postFrameCallback(frameCallback)
}
Use invalidate(Rect) para atualizações direcionadas, evite chamar invalidate() de onDraw() (loop infinito), e sempre faça perfil através de GPU Profile Rendering em um dispositivo. Isso mostrará o tempo exato de renderização de cada quadro e ajudará a identificar áreas problemáticas.
Perguntas frequentes
Não, chamar invalidate() dentro de onDraw() cria um loop infinito de redesenho: onDraw() chama invalidate(), que aciona onDraw() novamente. Isso leva a 100% de uso da CPU e queda de quadros. Use animações através de ValueAnimator ou Choreographer.
invalidate() funciona apenas na thread de UI e atualiza a flag dirty imediatamente. postInvalidate() envia uma solicitação através de Handler para a thread de UI e pode ser chamado de qualquer thread em segundo plano. Se você está na thread de UI — use invalidate() para latência mínima.
Sim, internamente o método setText() do TextView chama invalidate() após atualizar o texto. Se o texto alterar as dimensões da view, requestLayout() também é chamado. Os desenvolvedores não precisam chamar invalidate() manualmente ao trabalhar com widgets padrão.
Cada chamada a invalidate() agenda um redesenho no próximo Vsync (a cada 16 ms). Se onDraw() levar mais de 16 ms, ocorrem quedas de quadros. Otimize onDraw() — armazene Bitmaps em cache, evite alocações e use aceleração de hardware para renderização por GPU.
Sim, após alterar propriedades de Paint (cor, espessura, estilo), você deve chamar invalidate(), porque a View não rastreia automaticamente as alterações em objetos Paint. O sistema não sabe que o Paint mudou e não chamará onDraw() sem uma solicitação explícita.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também