Tecnologia

Introdução as Coroutines

Por: , outubro 11, 2018

Hoje vou estar falando um pouco sobre uma novidade que veio com a versão 1.1 do Kotlin, com a idéia de facilitar a vida do desenvolvedor quando o assunto é código assíncrono. Código assíncrono é algo bastante comum, não importa a linguagem na qual você está trabalhando. Sistemas conversam entre si e em vários momentos terão que aguardar algum resultado para poder dar continuidade no seu processamento. Por exemplo, imagine que você está utilizando uma Api onde você precisa validar suas chaves, receber um token, para então poder utilizar os serviços de forma autenticada.
Single Thread
Seu código poderia ser escrito mais ou menos assim: 


Esse código funcionaria, porém bloquearia a thread até que concluísse o processamento. Daí vai depender da sua aplicação se isso é impeditivo ou não. Lembrando que threads tem um custo e precisamos controlar quantas threads vamos ter rodando simultaneamente em nosso sistema.
Callbacks
Uma forma de evitar isso, seria utilizar callbacks. Nesse caso, ao invés de solicitar o token por exemplo e esperar que ele retorne, você apenas faz a requisição e passa a callback como parâmetro para a função e ela vai se certificar de chamar a callback passando o resultado assim que possível. O código ficaria mais ou menos assim:

Veja que esse código está bem simplificado, não está validando erros por exemplo e é super simples, mas em casos mais complexos, o código pode crescer bastante e mesmo com identação, o código pode ficar bem difícil de ler e dar manutenção, gerando o famoso “callback hell” ou “indent hadouken”.
RX
Outra opção seria usar uma das variações de Future que temos atualmente. Não importa o nome, (Rx / Future / Promise/ Deferred) a forma de funcionamento é sempre bastante parecida. Ao invés de receber uma callback como parâmetro para ser chamada no futuro como no exemplo anterior, nós temos uma classe que ficará responsável por fazer um “wrap” com o nosso resultado de forma que em algum momento no futuro quando o resultado for recebido, o nosso promise vai ser concluído, devolvendo o resultado esperado. Esse formato já fica bem mais sucinto que o anterior, porém cada library tem seus próprios nomes e seus vários “combinators” para cada situação e você vai precisar aprender e decorar vários deles, quase como re aprendendo a programar para conseguir fazer suas chamadas assíncronas. Um dos mais utilizados no Android é o RX, mas que muitas vezes acaba sendo utilizado apenas como uma forma de fazer requests de forma assíncrona, sendo que na verdade essa poderosa lib pode te oferecer muito mais recursos e acaba sendo subutilizada. O código do nosso exemplo ficaria mais ou menos assim no caso do uso do RX: 

Coroutines
Nesse cenário temos as Coroutines que facilitam muito esse trabalho, permitindo que você escreva seu código de forma sequencial da forma como vimos no nosso primeiro trecho de código e o Kotlin cuida do resto nos bastidores para impedir que o código bloqueie sua execução criando threads mais leves que as comuns. O único detalhe, é que anotamos nossa função com a palavra reservada “suspend” e a partir disso o Kotlin vai entender que deve tratar aquela função como uma co-rotina. Coroutines precisam de um contexto especial para rodar, portanto elas só rodam dentro de Coroutine Builders ou dentro de outras Coroutines. 

Launch
O Coroutine Builder launch, é a forma mais simples de usar coroutines. Dentro deste bloco você pode rodar suas suspend functions. Esse bloco retorna um Job, que você pode utilizar para cancelar a execução por exemplo. 

No exemplo acima, as imagens são carregadas uma de cada vez, a execução aguarda a conclusão de cada linha para poder serguir para a próxima instrução.
Async
O Coroutine Builder async é bastante similar ao launch, mas retorna um Deferred como retorno (Deferred estende de Job portanto tem as mesmas funcionalidades), e é a opção mais indicada quando você precisa fazer seu código de forma concorrente.

No exemplo acima, as duas imagens serão baixadas de forma simultânea, e assim que os dois downloads sejam concluídos, o método “setBackgrounds” é chamado.
A melhor parte em relação as Coroutines é que nós podemos ainda utilizar tudo que o Kotlin nos oferece, como loops, high-order functions, etc, sem mudar nada na forma de utilização, como um código sequencial qualquer. 

No código acima, estamos criando 100.000 execuções simultâens com alguma execução mais pesada que levará mais tempo para concluir, porém devido a forma como as Coroutines são organizadas, é possível rodar esse bloco de código sem problemas.
Bom, por hoje é isso. A idéia era dar uma breve descrição sobre Coroutines e sobre qual problema elas vem pra resolver. No próximo artigo desta série, vamos aprofundar um pouco mais no assunto e entender como as Coroutines funcionam “under the hood”. Até mais!

  • Receba nosso conteúdo em primeira mão.