Programação reativa em Flutter com Streams e RxDart parte 1

Nesse post eu pretendo abordar uma área que ainda é cinzenta no desenvolvimento de aplicativos com o Flutter , o gerenciamento de estado com Streams e RxDart.

Rully Alves
Flutter Brasil
3 min readSep 11, 2018

--

Algumas das dúvidas que tem “assolado” a comunidade, não só do Flutter, como também do React Native são:

  • Como eu devo gerenciar o estado ?
  • Confio no setState ?
  • Uso gerenciadores como o Redux , Mobx, etc… ?
  • Devo adicionar essa complexidade toda ao meu projeto?

Não! Use apenas Streams e Sinks para manter seu código simples.

Beleza , mas o que são Streams e Sinks ?

Streams não são nada mais que apenas fluxos e eventos, isso mesmo, você tem um fluxo de dados e adiciona outros dados a ele, a partir de eventos (não se preocupe, isso ficará mais claro a seguir).

Controladores de fluxo

A API de Streams do Flutter nos fornece o StreamController, que basicamente é quem fornece a capacidade de criar fluxos e adicionar eventos a eles , vou listar alguns dos métodos principais do StreamController:

StreamController controlador = new StreamController();

Ainda assim, isso não é o suficiente, pois o StreamController apenas envia eventos que aconteceram após a sua assinatura, ou seja, se você se inscreveu logo depois de um evento acontecer, você não recebe ele, por isso, no pacote RxDart nós temos outros controladores de fluxo, com funções diferentes, que são:

BehaviorSubject

Esse controlador de fluxo te dá sempre o valor mais atualizado do fluxo em questão, ou seja, sempre que você assina um fluxo, ele te dará o valor mais atual.

BehaviorSubject behavior = new BehaviorSubject();

ReplaySubject

Diferente do BehaviorSubject , esse controlador guarda todos os eventos ocorridos em um buffer. Então , quando você se inscreve nesse fluxo, você tem acesso a todos os valores que já passaram por ele.

ReplaySubject replay = new ReplaySubject();

PublishSubject

Funciona quase da mesma forma que o StreamController, ele envia os valores de fluxos que acontecem apenas após a sua inscrição nesse fluxo, ou seja, você perde quaisquer eventos que tenham ocorrido antes disso , porém ele usa um Observable ao invés de uma Stream , garantindo assim mais funções , como acumuladores como o scan , que é parecido com a função reducer do Javascript e outros , esse tópico será mais abordado no próximo post.

PublishSubject publish = new PublishSubject();

Quando você não precisar mais de um controlador , feche-o usando :

controlador.close();

Quando não mais precisar mais ouvir um fluxo, cancele sua assinatura :

fluxo.cancel();

Ouvindo um fluxo

O método listen, ou apenas “ouvir”, é o método principal de um controlador, ele, basicamente, ouve alterações naquele fluxo de dados e, a cada alteração, ele recebe o valor atual e pode executar funções com esse valor, exemplo:

controlador.stream.listen((dados){print(dados);});

Adicionando eventos a um fluxo

Para adicionar um evento a um fluxo, devemos usar o método :

controlador.sink.add(valor); 

Basicamente, esse método vai adicionar um valor ao fluxo, que passará a ter esse valor. O tipo de valor que pode ser adicionado a esse fluxo vai depender do tipo de valor declarado no controlador, porém também pode ser um valor dinâmico, se assim for declarado no controlador :

o controlador abaixo só emite e recebe fluxos de inteiros

StreamController<int> controlador = new StreamController<int>();

o controlador abaixo consegue receber e emitir fluxos de qualquer tipo de valor

StreamController controlador = new StreamController();

Tratando um fluxo

existem diversos métodos para o tratamento dos dados que vem de fluxos , nessa primeira parte eu irei abordar apenas alguns , existe um ótimo post sobre o assunto aqui : http://dartdoc.takyam.com/docs/tutorials/streams/

map :

o map funciona de forma parecida como funcionaria em um iterável , porém aqui ele executa uma função com cada valor daquele fluxo , como no exemplo abaixo :

controlador.stream.map((valor) => valor*2)).listen((dados){   print(dados);});

aqui ele executa uma função que multiplica todos os valores por 2 e depois escuta o fluxo.

where :

o where fornece uma condição para esse fluxo , ou seja , esse fluxo só vai emitir os valores adicionados a ele que forem maiores que 5

controlador.stream.where((valor) => valor > 5)).listen((dados){print(dados);});

Juntando tudo

Agora , vamos juntar todos os conceitos que vimos até agora e aplicar em um exemplo básico :

No próximo post eu abordar o uso da Pattern Bloc , StreamBuilder e outros , até lá xD .

--

--