Entrevistas de Android focam nos idioms do Kotlin, nas coroutines e no ciclo de vida da plataforma — a maioria das perguntas de nível sênior está, na verdade, testando se você entende que o seu processo pode ser encerrado a qualquer momento. Abaixo estão as perguntas mais feitas, cada uma com uma resposta modelo. Middle: compreensão mais profunda, otimização e situações reais de trabalho.
1
O que é uma coroutine, e como ela difere de uma thread?
Resposta
Uma coroutine é uma computação suspensível, agendada pelo runtime do Kotlin; uma thread é agendada pelo sistema operacional. A suspensão libera a thread em vez de bloqueá-la, então milhares de coroutines dividem um pool pequeno. É por isso que uma chamada bloqueante dentro de uma coroutine anula completamente o propósito dela — ela segura justamente a thread que deveria ter sido liberada.
2
O que é concorrência estruturada, e o que um CoroutineScope garante?
Resposta
Que toda coroutine iniciada em um scope é filha dele, então cancelar o scope cancela todas elas, e o scope não termina até que elas terminem. Na prática isso é o viewModelScope — o trabalho para quando o ViewModel é limpo. Iniciar no GlobalScope abre mão disso, e é assim que um trabalho sobrevive à tela que o iniciou.
3
Qual é a diferença entre Flow, StateFlow e SharedFlow?
Resposta
Um Flow é frio — produz valores quando é coletado, uma vez para cada coletor. StateFlow é quente, sempre tem um valor atual, e o emite para todo novo coletor, que é o que o estado de UI precisa. SharedFlow é quente, mas sem um valor atual, e serve bem para eventos que não deveriam se repetir — um comando de navegação ou um snackbar.
4
O que é recomposição no Compose, e o que faz ela acontecer demais?
Resposta
O Compose roda de novo os composables cujos inputs mudaram. Isso acontece demais quando uma lambda ou um tipo instável é recriado a cada render do pai, ou quando uma tela inteira lê um valor que muda com frequência. Os consertos são remember, elevar o estado para que só a parte que precisa dele o leia, e tipos estáveis — e os contadores de recomposição no Layout Inspector mostram exatamente onde.
5
Por que o Context que você mantém é uma fonte comum de vazamentos?
Resposta
Porque um Context de Activity está preso a uma tela, e qualquer coisa de vida longa que o segure mantém aquela tela inteira na memória. Os casos comuns são um singleton inicializado com uma Activity, uma referência estática, ou um listener nunca removido. O Context da aplicação é o certo para qualquer coisa que sobreviva a uma tela — mas ele não consegue inflar views com tema, e é por isso que o erro acontece.
6
Como você descobriria por que um app está lento para iniciar?
Resposta
Meça primeiro: adb shell am start -W dá os tempos de início frio, morno e quente, e o trace do sistema mostra o que roda antes do primeiro frame. As causas comuns são trabalho no Application.onCreate — inicialização de SDKs, principalmente — leituras síncronas de disco ou rede, e fazer na thread principal algo que poderia esperar até depois do primeiro frame.
7
Qual é a diferença entre launch e async?
Resposta
launch inicia um trabalho e retorna um Job sem resultado; async retorna um Deferred no qual você faz await. Use async só quando precisar do valor, e inicie os dois antes de dar await em qualquer um se quiser que rodem em paralelo. Um async cujo resultado nunca é esperado engole a própria exceção, uma forma silenciosa de perder um crash.
8
Serializable ou Parcelable — qual e por quê?
Resposta
Parcelable é o do Android: você descreve como o objeto é escrito e lido, então não há reflection, e é mensuravelmente mais rápido para passar dados entre componentes. Serializable é a interface marcadora do Java — quase de graça para escrever, lenta em runtime, e aloca bastante. Em Kotlin essa discussão praticamente desaparece porque o @Parcelize gera o boilerplate, o que elimina o único motivo real para escolher Serializable.
9
Doze, App Standby, WorkManager ou um Service — como escolher?
Resposta
Doze e App Standby são o sistema adiando seu trabalho em background quando o dispositivo está ocioso ou o app não está sendo usado, e é por isso que um alarme ou uma chamada de rede simplesmente não acontecem quando você esperava. WorkManager é para trabalho que pode ser adiado, mas precisa acontecer eventualmente e sobreviver à morte do processo e a um reboot — sincronização, upload, limpeza. Um foreground service é para trabalho que o usuário sabe que está acontecendo agora, como reprodução de mídia ou navegação, e precisa mostrar uma notificação. Recorrer a um background service comum no lugar disso é como o trabalho silenciosamente para de rodar no Android moderno.