Implementando Jetpack Navigation Component com Módulos de Features Dinâmicas no Android

Angélica Oliveira
Android Dev BR
Published in
6 min readJul 7, 2020

--

Simplificando a implementação de Dynamic Feature Modules em seu aplicativo Android

Photo by Joseph Barrientos on Unsplash

Módulos de features dinâmicas são uma forma de entregar aos seus usuários apenas as funcionalidades que realmente são necessárias e desejadas pelos mesmos, pois são instaladas somente quando são acessadas pela primeira vez.
Neste artigo, vou falar sobre como a Navigation Library pode ajudar na implementação de módulos com funcionalidades dinâmicas.

Para isso, irei usar como base meu artigo anterior, onde explico como e porque usar módulos dinâmicos, implementando-os utilizando um aplicativo baseado na navegação entre Activities do Android (sem usar a Navigation Library):

Mas por que Jetpack Navigation Component?

Se já havia um projeto com um módulo de feature dinâmica pronto, como fruto de meu artigo anterior, você deve estar se perguntando: “Humm, mas por que adicionar Jetpack Navigation Component agora?”.

Acredito que a resposta mais direta para essa pergunta seria:

Para simplificar e facilitar o desenvolvimento da comunicação entre o app base e um módulo de funcionalidade dinâmica.

Bom, o conjunto de libs responsáveis pela navegação do Android, como é possível ver na própria documentação, traz uma série facilitadores que ajudam na implementação da navegação entre telas de um aplicativo, desde interações através de um simples clique de botão, até padrões mais complexos.

Estes facilitadores, seguem um conjunto de princípios, visando melhorar a usabilidade de um aplicativo, deixando o padrão de navegação do mesmo mais consistente e previsível.

Migrando a implementação para utilizar Navigation Component

Apenas para relembrar, o aplicativo desenvolvido no artigo anterior, continha duas telas, a primeira com a listagem dos gifs retornados pela primeira página da API Trengind da Giphy, e a segunda com os gifs marcados como favoritos pelo usuário no app.

Ambas as telas eram implementadas utilizando Activities e apenas a segunda estava em um módulo de feature dinâmica. Sendo que o clique no botão do canto superior direito da tela era o responsável por iniciar a Activity do módulo dinâmico:

Imagem com a representação das duas telas desenvolvidas anteriormente, de listagem de gifs e exibição dos gifs favoritos

Como a aplicação desenvolvida tinha como base a comunicação entre duas Activities, e podemos ver que ambas pertencem a um mesmo fluxo, o caminho escolhido para utilizar a biblioteca de navegação do Jetpack foi migrar a lógica das Activities para Fragments, e usar apenas uma Activity como host da aplicação, ou seja, como o ponto de início do fluxo de navegação.

Essa migração foi feita em um commit, no qual a Jetpack Navigation Library também foi adicionada, de modo que a Activity host iniciasse a aplicação com o Fragment inicial com base em seu nav_graph:

Este arquivo é o responsável por definir para a aplicação qual é o fluxo de navegação, nele é possível atribuir as actions, deep links, e todos os destinos da app. Para sua edição e visualização, utilizamos o Navigation Editor, que além da opção de edição do arquivo .xml nos dá a possibilidade de verificar o gráfico de navegação de uma forma mais visual, que pode simplificar bastante a visualização do fluxo de um aplicativo! 😍 (emoji com olhos de coração)

Também é possível compor uma aplicação com vários navigation graphs, cada um representando determinado fluxo da app. Para o exemplo deste artigo, como se trata de um aplicativo bem pequeno com um fluxo de apenas duas telas, vamos trabalhar com apenas um navigation graph.

Para mais informações sobre como compor a aplicação com vários destinos e incluir mais de um navigation graph, recomendo a leitura da documentação oficial.

Implementação da Navegação com o Módulo Dinâmico

Até então, migramos boa parte do código da Activity principal para um Fragment, criamos uma Actity host e adicionamos a Navigation Library no módulo app. Porém, ainda não falamos sobre a navegação com o módulo de feature dinâmica, responsável por mostrar os Gifs marcados como favoritos.

Para isso, vamos iniciar modificando as dependências no módulo base app, adicionando a biblioteca responsável por implementar a navegação com Dynamic Feature Modules:

Notem que as dependências relativas a navegação estão sendo adicionadas via api, para que fiquem visíveis para o módulo dinâmico, que depende da base app.

Também é importante lembrar que estamos utilizando a versão 2.3.0 do componente de navegação, a mais recente até então. E para utilizar o Navigation Editor com o componente de navegação dinâmica, é necessário ter a versão 4.0 do Android Studio, ou mais recente.

Depois disso também foi necessário migrar o código referente a Activity da tela de listagem de Gifs favoritos, que se chamava FavoriteGifListActivity, para um Fragment, agora FavoriteGifListFragment.

Então, podemos adicionar o novo Fragment recém criado como um destino de nossa aplicação no gráfico de navegação da app, além de cadastrar a action que leva da tela principal para o módulo dinâmico. Assim o arquivo contendo o navigation graph da app fica da seguinte forma:

No código completo do gráfico de navegação, é possível ver que o novo Fragment adicionado, possui um campo a mais, chamado moduleName. Este atributo indica ao componente de navegação dinâmica que o destino se refere a uma tela de um dynamic feature module com o nome especificado no campo.

Também, é necessário modificar as instâncias de NavHostFragment para androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment. Isso foi feito no código do layout .xml da Activity host da app:

Tendo feitas estas modificações, chegou a hora de implementar a ação de clique no botão na Activity principal, pois se trata de um botão na Action Bar, cuja lógica não foi movida para o Fragment.

Como recordar é viver, vamos relembrar a implementação anterior da ação deste botão, sem a Navigation Library. Ela continha uma lógica que verificava se o módulo de feature dinâmica estava instalado. Se não, o download era realizado e posteriormente a sua instalação, isso tudo por meio de um controle realizado na própria Activity:

Além deste código, vocês podem ver que haviam mais métodos e componentes de layout implementados, para possibilitar a comunicação do progresso de download e instalação do módulo dinâmico ao usuário.

Agora, substituindo a lógica anterior pela implementação com o componente de navegação do Jetpack o código do listener exibido acima e todos os métodos auxiliares responsáveis por verificar e informar o usuário sobre a instalação do módulo podem ser DELETADOS! Todas as alterações feitas podem ser visualizadas neste commit, com 44 adições e 225 remoções.

Imagem de um cachorro feliz

A felicidade vista na imagem acima traduz bem a satisfação em simplificar um código que não parecia tão bacana, uma lógica na Activity que pode ser melhorada! 😃 (emoji sorrindo)

Depois então de remover essa lógica e ficarmos mega felizes. Vamos implementar a ação do botão utilizando a action criada pelo componente de navegação, fica tão simples quanto isso:

A ação de navegar para um módulo dinâmico utilizando o componente de Navigation já contempla as atividades de verificar se o módulo está instalado, baixar e instalar caso necessário, exibindo um Fragment básico de progresso para informar o usuário sobre o download e instalação do módulo:

Imagem do Fragment de instalação do módulo dinâmico

Agora, você deve estar pensando: “Mas e se for necessário implementar uma visualização customizada do progresso de download e instalação do módulo dinâmico?”

Bom, também é possível! Neste caso há a possibilidade de customizar um Fragment que deriva de AbstractProgressFragment e realizar as alterações necessárias, ou então instanciar a classe DynamicInstallMonitor observando os diferentes estados do campo status, um LiveData responsável por informar o atual estado da instalação do módulo.

Então acredito que seja isso, pessoal! Espero que tenham gostado, e se animado ainda mais para utilizar essa nova forma de se entregar aplicativos Android para nossos queridos usuários. 😉 (emoji piscando)

Ah, toda a implementação descrita neste artigo está em meu Github, caso tenham dúvidas podem ficar a vontade para consultar, ou entrar em contato comigo:

Até mais!

--

--

Angélica Oliveira
Android Dev BR

Android Engineer @Spotify | Google Developer Expert for Android. Learning and sharing knowledge.