Android Tips! Utilizando coroutines.flow com Firebase

Rodrigo Vianna Calixto de Oliveira
CodandoTV
Published in
3 min readApr 14, 2022

Para quem usa o Firebase sabe que normalmente a forma que pode ser utilizada os callbacks não é muito adequado para encaixar no seu projeto — principalmente quando possui camadas e arquiteturas definidas fazendo com que precise ser feito algum tipo de adaptação para esta tecnologia — por exemplo: quem é do tempo do RX, pode estar acostumado com a criação de soluções próprias criando seu Single.create para pode emitir no sucesso(.onSuccess) ou emitir quando acontece um erro(.onError), e até utilizando algumas bibliotecas que existem como: RxFirebase, RxStore, RxFirestore entre muitas outras que devem ter por ai.

A ideia é mostrar essa adaptação utilizando Flow, pois já faz um tempo que venho trabalhado com o coroutines.flow, e ao utilizar com o Firebase fiz uma solução utilizando o DynamicLink, mas o principio é o mesmo para qualquer funcionalidade do Firebase até porque todas são uma Task<TResult> que tem um addOnSuccessListener, addOnFailureListener e um addOnCompleteListener.

Bom, vamos entender os pontos mais pertinentes deste código.

Na linha 1, está utilizando um suspend devido a ser um coroutines e na mesma linha esta sendo chamado um callbackflow onde é criado uma instância de um coldFlow, isto é, o bloco é chamado toda vez que o operador for aplicado, mas para que isso funcione é necessário a implementação da o awaitClose() que está na linha 19 fazendo com que após a execução do Firebase ela não feche o canal imediatamente evitando qualquer tipo de vazamentos de memória, caso contrário, o retorno de chamada pode continuar em execução mesmo quando o coletor de fluxo já tiver sendo concluído. Desta forma após o retorno do Firebase é possível emitir o dado apenas para o interessado em recebe-lo.

Note também que na linha 13 e 17 esta dando um close(), isso é para previnir que o canal fique aberto mesmo você não tendo mais interesse de uso.

E na linha 6 é a emissão do retorno do que você precisa para continuar o flow.

Como testar isso?

Estou utilizando o mockk para me auxiliar nos testes unitários para quem não conhece vou deixar o link https://mockk.io, e com ela estou mockando os seguintes valores que vou utilizar para meu teste na linha 4,5,6 e 8, com uma observação que na linha 4 é a biblioteca do Firebase em questão que esta sendo passada pelo construtor na linha 12.

Caso tenha reparado estou utilizando nas referências do Firebase o relaxed, basicamente ele auxilia na implementação de todo meu objeto automaticamente fazendo com que eu foque apenas no que eu quero testar.

Na linha 18 até 21 é onde é montado os retornos esperados.

Na linha 23 é a inicialização do job para poder depois finalizar na linha 31.

Na linha 26 é basicamente comparação se os ids esperados são iguais.

Pronto, agora que a parte mais tranquila foi, vamos focar no fluxo que interessa que é validar que esta funcionando a sua chamada.

Conforme está na linha 7, esta sendo criado um slot do TResult de sucesso da biblioteca do Firebase isso quer dizer que esta criando um espaço vazio para poder aceitar algo que fique alojado dentro dele, aguardando para ser usado. Para começar a ligar o que foi montado a linha 18 utiliza um capture(slot) fazendo com que a task que esta sendo mockada ao ser chamado quando for executado o nosso método na linha 19, e quando nossa classe chama nosso método ele fará todo esse fluxo automaticamente validando que o listener me retornou um sucesso atrás da linha 30 retornando nosso pending e depois retorna uma URI até chegar no valor do tipo de getQueryParameter e booooooom.

Tomara que tenha ajudado, lembrando que essa solução funciona para todos os tipos de produtos do Firebase como: Store, RemoteConfig, Auth entre outros.

E você como faria essa solução? Deixe nos comentários!

Agradeço e se tiver qualquer feedback, deixa ai nos comentários ou entre em contato comigo no LinkedIn ou https://flow.page/rviannaoliveira.

--

--