Sobes.tech
Middle

Que capacidades o Kotlin oferece para trabalhar com operações assíncronas?

sobes.tech IA

Resposta da IA

A Kotlin fornece corrotinas para simplificar operações assíncronas, oferecendo threads leves que não bloqueiam o thread principal.

Funcionalidades principais:

  • Funções de Suspensão: Funções com a palavra-chave suspend, que podem ser suspensas e retomadas. Elas não bloqueiam o thread em que são executadas.
    suspend fun fetchData(): String {
        delay(1000) // Simula uma operação longa
        return "Dados recebidos"
    }
    
  • Construtores de Corrotinas: Funções usadas para lançar corrotinas:
    • launch: Inicia uma nova corrotina e retorna um Job (não bloqueante).
      GlobalScope.launch {
          println("Corrotina lançada")
      }
      
    • async: Inicia uma nova corrotina e retorna um Deferred<T> (bloqueante ao chamar .await()).
      val deferred = GlobalScope.async {
          fetchData()
      }
      // ...
      val result = deferred.await() // Aguarda o resultado
      
    • runBlocking: Bloqueia o thread atual até que a corrotina termine (usado em pontes entre código bloqueante e não bloqueante, por exemplo, em testes).
      runBlocking {
          val data = fetchData()
          println(data)
      }
      
  • Contexto de Corrotina: Conjunto de elementos que definem o comportamento da corrotina, incluindo Dispatcher e Job.
    • Dispatcher: Define o thread ou pool de threads onde a corrotina é executada.
  • Dispatchers: Objetos embutidos para gerenciar threads:
    • Dispatchers.Default: Pool geral de threads de fundo.
    • Dispatchers.IO: Otimizado para entrada/saída (operações de disco, rede).
    • Dispatchers.Main: Thread principal de UI (para Android, JavaFX, etc.).
    • Dispatchers.Unconfined: Executa a corrotina no thread atual, mas pode retomar em qualquer thread após suspensão.
    GlobalScope.launch(Dispatchers.IO) {
        // Executa na thread de entrada/saída
    }
    
  • Concorrência Estruturada: Princípio segundo o qual as corrotinas têm um pai (CoroutineScope) e são canceladas automaticamente ao cancelar o pai. Evita vazamentos de recursos e simplifica a gestão do ciclo de vida.
    // CoroutineScope gerencia automaticamente as corrotinas filhas
    val scope = CoroutineScope(Dispatchers.Default)
    val job = scope.launch {
        // ...
    }
    // Ao cancelar o scope, todas as corrotinas filhas são canceladas
    scope.cancel()
    
  • Canais: Para transferência segura de dados entre corrotinas. Podem ser:
    • Sem buffer: A recepção ocorre somente após o envio.
    • Bbuffered: Permite enviar vários elementos antes de bloquear.
    • Conflated: Armazena apenas o último elemento enviado.
    val channel = Channel<Int>()
    
    scope.launch {
        for (x in 1..5) channel.send(x)
        channel.close()
    }
    
    scope.launch {
        for (y in channel) println(y)
    }
    
  • Flow: Fluxo de dados que pode emitir vários valores assincronamente. Semelhante ao Observable do RxJava, mas mais leve e integrado com corrotinas.
    fun simpleFlow(): Flow<Int> = flow {
        for (i in 1..3) {
            delay(100)
            emit(i) // Envia valor
        }
    }
    
    runBlocking {
        simpleFlow().collect { value -> println(value) } // Consome valores
    }
    

Essas funcionalidades permitem escrever código assíncrono em estilo imperativo, tornando-o mais legível e fácil de manter em comparação com o uso de callbacks ou Future.