Sobes.tech
Middle+

Que problemas inesperados podem surgir ao trabalhar com corrotinas no Android?

sobes.tech IA

Resposta da IA

  • Cancelamento inesperado: A coroutine pode ser cancelada implicitamente, por exemplo, ao alterar a configuração do dispositivo ou fechar uma Activity/Fragment, se o contexto do ciclo de vida não for gerido cuidadosamente. Isto pode levar a fugas de memória ou operações não concluídas.
  • Problemas com o contexto (propagação do contexto): A transferência do contexto de coroutine entre camadas da aplicação (UI, ViewModel, Repository) requer atenção. Uso incorreto do contexto pode causar bloqueios na UI ou bloqueios de threads.
  • Fugas de recursos por exceções não tratadas: Exceções não controladas em coroutines filhas podem cancelar implicitamente o pai, mas os recursos alocados dentro da filha podem não ser libertados.
  • Fluxos "frios" (Flow) e sua gestão do ciclo de vida: Flow é preguiçoso por natureza e requer recolha ativa de dados. Se a recolha não for gerida corretamente (por exemplo, com flowWithLifecycle ou collectLatest), pode resultar em comportamentos indesejados ao alterar o estado da UI ou ciclo de vida.
  • Chamadas bloqueantes: Incluir chamadas bloqueantes (como operações de rede ou ficheiros) numa coroutine que é executada no dispatcher principal (Dispatchers.Main) levará a um ANR.
// Exemplo de potencial problema com cancelamento de coroutine ao alterar a configuração
class MyViewModel : ViewModel() {
    fun loadData() {
        viewModelScope.launch {
            // Operação prolongada
            delay(5000)
            // Se a Activity for recriada durante o delay, esta linha pode não ser executada
            println("Dados carregados")
        }
    }
}

// Exemplo de chamada bloqueante no dispatcher Main
import kotlinx.coroutines.*

fun performBlockingOperation() {
    runBlocking { // Não usar na thread UI!
        delay(1000) // Bloqueia a thread
    }
}

// Deve ser assim:
fun performNonBlockingOperation() {
    CoroutineScope(Dispatchers.Default).launch {
        delay(1000) // Não bloqueia a thread principal
    }
}