O que é launch em Kotlin?
O launch é um coroutine builder que inicia uma nova coroutine sem retornar resultado. Ele é do tipo “fire-and-forget” — você dispara a coroutine e segue em frente. Perfeito pra tarefas que precisam rodar em background mas não precisam devolver um valor.
O launch retorna um Job, que permite controlar o ciclo de vida da coroutine: cancelar, esperar terminar ou verificar o status.
Exemplo básico
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
println("Coroutine iniciada")
delay(1000)
println("Coroutine finalizada")
}
println("Código principal continua...")
job.join() // Espera a coroutine terminar
}
Saída:
Código principal continua...
Coroutine iniciada
Coroutine finalizada
Controlando com Job
O Job retornado pelo launch oferece várias possibilidades:
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
repeat(100) { i ->
println("Processando item $i")
delay(200)
}
}
delay(1000)
println("Cansou de esperar!")
job.cancel()
println("Job cancelado: ${job.isCancelled}")
}
Dispatchers
Você pode escolher em qual thread a coroutine vai rodar:
import kotlinx.coroutines.*
fun main() = runBlocking {
launch(Dispatchers.Default) {
println("CPU-intensivo em: ${Thread.currentThread().name}")
}
launch(Dispatchers.IO) {
println("Operação de I/O em: ${Thread.currentThread().name}")
}
}
Dispatchers.Default— tarefas pesadas de CPUDispatchers.IO— operações de entrada/saídaDispatchers.Main— thread principal (Android)
launch vs async
A diferença é simples: launch não retorna valor, async retorna. Se você precisa do resultado da coroutine, use async. Se é só pra executar algo no background, launch resolve.
// Não precisa do resultado? Use launch
launch { salvarNoLog("evento_123") }
// Precisa do resultado? Use async
val dados = async { buscarDados() }
println(dados.await())
Structured Concurrency com launch
O launch respeita o conceito de structured concurrency do Kotlin. Isso significa que uma coroutine filha está vinculada ao escopo pai. Se o escopo pai for cancelado, todas as coroutines filhas também são canceladas automaticamente.
import kotlinx.coroutines.*
fun main() = runBlocking {
val escopo = CoroutineScope(Dispatchers.Default)
val jobPai = escopo.launch {
launch {
delay(2000)
println("Filha 1 terminou") // Nunca será impresso
}
launch {
delay(2000)
println("Filha 2 terminou") // Nunca será impresso
}
}
delay(500)
jobPai.cancel() // Cancela o pai e todas as filhas
println("Todas as coroutines foram canceladas")
}
Tratamento de exceções com launch
Diferente do async, onde exceções são lançadas ao chamar await(), no launch as exceções propagam imediatamente para o escopo pai. Para interceptá-las, use um CoroutineExceptionHandler:
import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, excecao ->
println("Exceção capturada: ${excecao.message}")
}
val escopo = CoroutineScope(Dispatchers.Default + handler)
escopo.launch {
throw RuntimeException("Algo deu errado!")
}
delay(500) // Aguarda para ver a saída
}
Casos de Uso no Mundo Real
- Envio de analytics e telemetria: disparar eventos de rastreamento sem bloquear a interface do usuário. O resultado do envio não importa para o fluxo principal da aplicação.
- Sincronização periódica de dados: usar
launchdentro de um loop comdelaypara sincronizar dados com o servidor a cada intervalo de tempo, como atualizar cache local. - Processamento de filas: consumir itens de uma fila (mensagens, notificações, tarefas) em background, processando cada item de forma independente sem precisar do resultado.
- Atualização de UI no Android: disparar operações de atualização de tela a partir do
viewModelScope.launch, garantindo que a coroutine seja cancelada automaticamente quando o ViewModel for destruído.
Boas Práticas
- Sempre use
launchdentro de um CoroutineScope bem definido. Evite usarGlobalScope.launch, pois ele não respeita o ciclo de vida da aplicação e pode causar vazamentos de memória. - Prefira
Dispatchers.IOpara operações de rede e disco, eDispatchers.Defaultpara cálculos pesados. Nunca faça operações bloqueantes noDispatchers.Main. - Utilize
job.join()quando precisar garantir que a coroutine terminou antes de prosseguir, mas evite usá-lo excessivamente — isso anula a vantagem da concorrência. - Trate exceções com
CoroutineExceptionHandlerou blocostry/catchdentro dolaunchpara evitar crashes inesperados. - Use
supervisorScopequando quiser que a falha de uma coroutine filha não cancele as irmãs.
Erros Comuns
- Usar
GlobalScope.launchindiscriminadamente: isso cria coroutines que vivem durante toda a aplicação, podendo causar vazamentos de memória e comportamentos inesperados. - Esquecer de cancelar coroutines: não vincular o
launcha um escopo com ciclo de vida definido faz com que coroutines continuem rodando mesmo depois que a tela ou componente foi destruído. - Ignorar exceções: como o
launchpropaga exceções para o escopo pai, não tratá-las pode derrubar toda a aplicação silenciosamente. - Bloquear a thread dentro do
launch: usarThread.sleep()em vez dedelay()bloqueia a thread e desperdiça os benefícios das coroutines. - Confundir
launchcomasync: tentar obter um resultado delaunchnão funciona. Se precisa de retorno, useasynccomawait().
Perguntas Frequentes
O launch bloqueia a thread? Não. O launch inicia a coroutine de forma assíncrona e retorna imediatamente um Job. A thread que chamou o launch continua executando o código seguinte sem esperar.
Quando usar launch em vez de async? Use launch quando a tarefa não precisa devolver um resultado para quem a iniciou. Exemplos: salvar logs, enviar eventos de analytics, atualizar cache. Se precisa do valor de retorno, use async.
O que acontece se uma exceção ocorrer dentro do launch? A exceção é propagada para o escopo pai. Se não houver tratamento, ela pode cancelar todo o escopo e suas coroutines filhas. Use CoroutineExceptionHandler ou try/catch interno para lidar com isso.
Posso usar launch fora de um CoroutineScope? Não. O launch é uma função de extensão de CoroutineScope. Você precisa de um escopo como runBlocking, viewModelScope, lifecycleScope ou um CoroutineScope customizado.
Termos Relacionados
- Coroutine — o conceito fundamental de concorrência leve em Kotlin
- Suspend — funções que podem ser pausadas e retomadas dentro de coroutines
- Async — coroutine builder que retorna um resultado via
Deferred - Flow — streams assíncronos reativos baseados em coroutines
launch é provavelmente o coroutine builder que você mais vai usar no dia a dia.