withContext — é uma função de alternância de contexto dentro de uma corrotina que altera temporariamente a thread ou dispatcher para um bloco de código especificado e retorna o resultado ao contexto original. De acordo com JetBrains, 2025, withContext é uma das ferramentas de corrotinas mais usadas para requisições de rede e operações de disco. A função garante que, após a conclusão do bloco, a corrotina continue a execução no dispatcher original, evitando erros acidentais de segurança de thread.
Principais pontos
withContext é uma função suspensa do pacote kotlinx.coroutines que executa o bloco de código fornecido em um CoroutineContext especificado e retorna o resultado ao contexto original. A assinatura da função é a seguinte:
suspend fun withContext (
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T
O parâmetro context aceita qualquer CoroutineContext — mais comumente um dos Dispatchers.IO, Dispatchers.Default ou Dispatchers.Main padrão. O bloco é executado nesse contexto, e o resultado é retornado para onde withContext foi chamado.
Após a conclusão da lambda, withContext alterna garantidamente a execução de volta para o dispatcher original. Isso significa que o desenvolvedor não precisa chamar manualmente withContext(Dispatchers.Main) após uma operação em segundo plano — o retorno ocorre automaticamente. Esse comportamento está documentado na especificação do Kotlin Coroutines desde a versão 1.3.
O desenvolvimento Android é a principal área de uso do withContext. Um cenário típico: um ViewModel inicia uma corrotina na thread principal, dentro chama withContext(Dispatchers.IO) para uma requisição de rede, e o resultado após o retorno automático ao Main é usado para atualizar a UI. Essa abordagem é a base da arquitetura MVVM e é recomendada pelo Google no guia oficial de corrotinas.
Para entender o withContext, você precisa entender o CoroutineContext e seu componente chave — o dispatcher. Cada corrotina tem um conjunto de elementos de contexto, entre os quais o dispatcher determina em qual thread ou pool de threads o código é executado.
| Dispatcher | Propósito | Tamanho do pool |
|---|---|---|
| Dispatchers.Main | Thread principal da UI (Android, JavaFX, Swing) | 1 (thread principal) |
| Dispatchers.IO | Operações de disco e rede | 64 threads (limite cresce) |
| Dispatchers.Default | Cálculos intensivos de CPU | max(2, número de núcleos) |
| Dispatchers.Unconfined | Sem thread fixa | ilimitado |
É importante entender que withContext não cria uma nova corrotina — ele apenas alterna o contexto para a existente. Essa é uma diferença chave de launch e async, que geram novas corrotinas. A implementação interna do withContext é otimizada: se o contexto solicitado corresponder ao atual, nenhuma alternância ocorre — a função executa no mesmo dispatcher.
Dispatchers.Main dentro de withContext(Dispatchers.Main) não causa alternância — o Kotlin Coroutines reconhece a identidade dos contextos e pula a operação desnecessária. Da mesma forma, withContext(Dispatchers.Default) dentro de uma corrotina já executando em Default não cria sobrecarga. Essa otimização é implementada em ContinuationInterceptor.
Iniciantes frequentemente confundem withContext com launch e async, já que as três funções trabalham com corrotinas e contexto. No entanto, seus propósitos são fundamentalmente diferentes.
| Característica | withContext | launch | async |
|---|---|---|---|
| Cria nova corrotina | Não | Sim | Sim |
| Retorna resultado | Sim (T diretamente) | Não (Job) | Sim (Deferred<T>) |
| Execução | Sequencial | Paralela | Paralela |
| Espera do resultado | Automática | join() | await() |
| Caso de uso típico | Alternar dispatcher | Fire-and-forget | Cálculos paralelos |
Se você precisa executar uma operação em uma thread de fundo e obter um resultado — use withContext. Se você precisa executar várias operações independentes em paralelo — use async com await. Se você não precisa do resultado (logging, escrita de cache) — use launch. O Google recomenda withContext como a ferramenta preferida para a camada de Repository na arquitetura Android.
Vamos ver três cenários práticos de uso do withContext em aplicações Android com Kotlin. Cada exemplo demonstra uma tarefa específica e o padrão correto.
Um ViewModel chama um método do repositório de uma corrotina no Main. Dentro, withContext(Dispatchers.IO) realiza uma requisição HTTP, e o resultado é retornado automaticamente:
class UserRepository(
private val api: UserApi
) {
suspend fun getUser(id: String): User {
return withContext(Dispatchers.IO) {
api.fetchUser(id)
}
}
}
A corrotina no ViewModel chama getUser como qualquer função suspensa normal — sem especificar explicitamente o dispatcher. withContext esconde os detalhes da alternância de threads.
Quando você precisa executar várias operações de IO uma após a outra, withContext as combina em um único bloco. Isso é mais eficiente do que envolver cada operação em um withContext separado:
suspend fun loadUserProfile(id: String): Profile {
return withContext(Dispatchers.IO) {
val user = api.fetchUser(id)
val posts = api.fetchPosts(id)
Profile(user, posts)
}
}
Ambas as operações executam em Dispatchers.IO, e o resultado Profile é criado e retornado sem alternâncias de contexto desnecessárias. Se as operações são independentes, é melhor usar async para execução paralela.
Em alguns cenários, você precisa executar código que não pode ser cancelado — por exemplo, salvar estado ao fechar uma tela. A combinação de withContext + NonCancellable resolve essa tarefa:
withContext(Dispatchers.IO + NonCancellable) {
cache.saveState(state)
analytics.logEvent("state_saved")
}
O operador + combina dois elementos de contexto: o dispatcher IO e a flag NonCancellable. O bloco executa mesmo se a corrotina pai foi cancelada — útil para operações de finalização.
A implementação interna do withContext baseia-se no mecanismo Continuation — a abstração central das corrotinas Kotlin. Cada ponto de suspensão salva o estado de execução em um objeto Continuation, e withContext não é exceção.
O compilador Kotlin traduz withContext em uma chamada ao método withContext de kotlinx.coroutines, que internamente cria uma nova instância de DispatchedContinuation. Este objeto envolve o Continuation original e substitui seu dispatcher. Se o novo dispatcher difere do atual, a execução é suspensa, o bloco é enviado ao pool de threads correspondente e, após a conclusão — retoma com o contexto original.
Quando withContext é chamado com o mesmo dispatcher em que a corrotina já está executando, Kotlin ativa fast-path: o bloco executa sincronamente, sem criar um DispatchedContinuation e sem enviá-lo ao pool de threads. Isso torna withContext praticamente gratuito para chamadas repetidas com o mesmo contexto. De acordo com benchmarks da JetBrains (kotlinx.coroutines 1.8), o fast-path é concluído em menos de 0.1 µs.
Cada chamada a withContext com um dispatcher diferente cria um novo DispatchedContinuation e requer alternância de thread — isso leva de 1 a 5 µs dependendo da carga. Para a maioria das aplicações, esse atraso é imperceptível, mas dentro de loops com milhares de iterações, vale a pena agregar operações em um único bloco withContext.
Mesmo desenvolvedores experientes cometem erros ao trabalhar com withContext. Vamos ver quatro problemas mais comuns e como preveni-los.
Desenvolvedores frequentemente envolvem cada linha em um withContext separado em vez de combinar as operações em um único bloco. Cada chamada extra com um dispatcher diferente cria sobrecarga.
Correto: combinar operações IO sequenciais em um único withContext(Dispatchers.IO) { ... }. Se algumas operações são intensivas em CPU — use withContext(Dispatchers.Default) dentro do mesmo bloco.
withContext executa código sequencialmente. Se duas requisições de rede independentes estão envolvidas em um withContext, elas executarão uma após a outra. Para paralelismo, use async + await.
// Sequencial — lento
withContext(Dispatchers.IO) {
val a = api.fetchA()
val b = api.fetchB()
}
// Paralelo — rápido
coroutineScope {
val a = async { api.fetchA() }
val b = async { api.fetchB() }
println("${a.await()} ${b.await()}")
}
Se uma corrotina é cancelada durante withContext, o bloco em Dispatchers.IO também é interrompido. Para operações que devem ser concluídas a todo custo (escrita em BD, envio de análises), combine withContext com NonCancellable.
Nunca atualize componentes de View dentro de withContext(Dispatchers.IO). withContext não retorna ao Main até que todo o bloco seja concluído. Coloque as atualizações de UI após a chave de fechamento do withContext — então a corrotina já estará na thread principal.
Perguntas frequentes
withContext é uma função suspensa que não bloqueia a thread, mas alterna o contexto dentro de uma corrotina existente. runBlocking é uma ponte entre corrotinas e código normal que bloqueia a thread atual até a conclusão. withContext é seguro para a thread de UI, runBlocking não.
Não, withContext é uma função suspend, portanto só pode ser chamada de outra função suspend ou de uma corrotina (launch/async). De uma função normal, withContext não pode ser chamado — para isso você precisa de runBlocking ou CoroutineScope.
Kotlin ativa fast-path — o bloco executa sincronamente na mesma thread sem alternância. A sobrecarga é menor que 0.1 µs. Isso não é um erro, mas tal chamada é redundante — é melhor simplesmente executar o código sem withContext.
Exceções dentro de withContext propagam-se da mesma forma que no código normal — através de try-catch. Se o bloco lançar uma exceção, ela propaga para a corrotina pai e a cancela se não for tratada. Use try-catch dentro de withContext ou ao redor dele.
Não, withContext não cria uma nova corrotina. Ele usa a corrotina existente mas altera temporariamente seu contexto. Isso o diferencia de launch e async, que geram corrotinas filhas. Esse comportamento é confirmado pelo código-fonte do kotlinx.coroutines.
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