Arquitetura Android Moderna: Utilizando Single Activity Pattern

William Amaral
Android Dev BR
Published in
5 min readJan 4, 2023
Representa uma arquitetura cívil moderna na cor prata em um fundo preto
Photo by JuniperPhoton on Unsplash

Se você já trabalha com Android, ou está começando seus estudos, provavelmente já conhece as Activities, presentes desde sempre no desenvolvimento android nativo, elas fornecem os meios para que as pessoas possam interagir com nossos aplicativos através da UI (Interface de Usuário).

Geralmente, quando começamos a desenvolver uma nova aplicação, a tendência é utilizarmos uma Activity para representar cada "tela" do nosso app. Como por exemplo:

Imagem que representa três Activities, da direita para a esquerda: HomeActivity, ProductActivity e SettingsActivity. Todas em um fundo na cor preta representando telas de um aplicativo.
Exemplo de Activities em um aplicativo

Com o passar do tempo e com aplicações cada vez maiores e complexas, logo teremos muitas Activities em nosso projeto, e cada uma com suas n responsabilidades. O que não é ruim, dado que, desde sempre trabalhamos desse modo ao se utilizar o framework android. Mas em se tratando de projetos que temos a pretensão de escalabilidade, quanto mais simples e funcional for nossa arquitetura, mais fácil será sua manutebilidade futuro.

Arquitetura Single Activity, a salvação?

Na documentação oficial do Android Developers, o time do Google, aborda algumas recomendações de arquitetura e boas práticas, utilizando alguns conceitos modernos, com o objetivo de melhorar a qualidade e robustez dos nossos aplicativos, uma dessas recomendações, é justamente o assunto desse artigo, a utilização de uma arquitetura baseada em uma activity (ou o mínimo possível).

Em resumo, essa abordagem consiste em termos uma activity que servirá como um containêr para os vários fragmentos que irão compor as demais telas do app.

Veja mais sobre Activities e Fragments aqui.

Para ficar mais claro, imagine um aplicativo que existá 3 (três) telas (login, cadastro e home), ao invés de utilizarmos três Activities (uma para cada tela), podemos ter uma Activity principal (MainActivity) e todas as demais telas podem ser Fragments. Com isso teremos mais flexibilidade para trabalhar em nosso app e compartilhar os dados entre elas.

Representação gráfica de três fragmentos: FragmentLogin, FragmentRegister e FragmentHome. Todos ligados por uma seta à um container com o nome MainActivity, com os dizeres: Cada Fragment será exibido no contâiner da MainActivity.

Alguns pontos importantes sobre essa abordagem:

  1. Não há a necessidade de sempre registrar uma nova activity no manifest.xml, dado que só teremos uma no projeto todo;
  2. A navegação entre as UIs fica mais fácil de lidar, pois não precisamos lidar com isso manualmente, basta utilizar o Jetpack Navigation Component;
  3. Facilidade em compartilhar o estado, visto que os fragmentos estarão delimitados à mesma activity;
  4. Podemos delimitar quais rotas (destinos) cada tela poderá fazer, por exemplo, uma tela de login, só poderia enviar a pessoa para a tela de cadastro e nenhuma outra;

E sobre a implmentação?

Esse artigo não entrará em detalhes de implementação, veremos apenas alguns dos pontos mais importantes — Veja aqui os detalhes na documentação oficial.

Para que possamos implementar essa abordagem, deveremos utilizar a biblioteca Jetpack Navigation Component, ela irá nos fornecer um sistema de navegação fluído e robusto.

Todo esse sistema é composto de três partes fundamentais:

  1. NavigationGraph (Gráfico de navegação)
  2. NavigationHost (Host de navegação)
  3. NavController (Controle de navegação)

O NavigationGraph é um aquivo .xml que deverá conter todas as informações referentes aos destinos que o aplicativo terá, você pode entender os destinos, como as possíveis áreas do app (rotas).

O NavigationHost por sua vez, é um contêiner vazio em que os destinos serão substituídos por outros e tudo isso será gerenciado pelo NavController. Abaixo você pode ter uma ideia do funcionamento de todas essas partes juntas:

Representação do funcionamento do componente de navegação. FragmentA, FragmentB e FragmentC, todos ligados por uma seta à um ícone de engrenagem escrito: NavController, que está ligado por uma seta à um container NavHost, com os dizeres: Gerencia a navega;cão e troca o conteúdo de NavHost pelos destinos.
Representação de como funciona a troca de destinos

O primeiro passo, logo após a instalação das dependências, é a criação do gráfico de navegação, como no exemplo abaixo:

Como já foi dito acima, este arquivo define os possíveis destinos que o fluxo de navegação terá, e também as actions (ações, representadas pelas setas, na imagem abaixo), que funcionam como pontes entre cada um dos fragments.

Um recurso bastante útil para nos ajudar na visualização de como está ficando nosso gráfico, é a utilização do Navigation Editor do Android Studio, esssa ferramenta nos permite visualizar todos os destinos de navegação disponíveis e até editá-los, o que torna o desenvolvimento mais ágil.

Imagem com fundo escuro, contendo 4 telas de um aplicativo, representando cada um dos possíveis destinos de navegação, elas estão ligadas por setas, que representam as ações de navegação.
Visualizaação do gráfico de navegação utilizando a ferramenta Navigation Editor

Após a definição de todos os possíveis destinos do app, precisamos adicionar o componente de NavHost à MainActivity, para que o sistema de navegação possa trocar o conteúdo pelos destinos corretos, como exemplificado abaixo:

Um ponto interessante a se notar, é a facilidade de utilização dos componentes de navegação, como a BottomNavigationView. Cada um dos destinos definidos no NavGraph, possuem um ID único, quando utilizamos esse mesmo ID nos items de menu, que compõem a barra de navegação, o NavigationComponente irá realizar a navegação para as demais telas, de forma automática.

Neste exemplo, os IDs: homeFragment e myQuotesFragment, já foram definidos no gráfico de navegação, quando a pessoa tocar em algum item do menu, o sistema de navegação irá redirecionar para o fragmento correspondente.

Representação de uma tela de um aplicativo utilizando a BottomNavigationView

Esse funcionamento só é possível, graças a uma classe chamada NavigationUI, que é a responsável por gerenciar os componentes de navegação das interfaces. Para entender como ela funciona, dê uma olhada aqui.

Finalizando

Importante notar que tudo o que falamos até aqui, são apenas recomendações de como podemos ter uma estrutura mais simples e concisa utilizando a abordagem de única Activity e como a biblioteca de navegação de componentes pode nos ajudar, existem ainda outras formas de melhorar a arquitetura de um projeto e sempre caberá a você decidir o que utilizar e em qual momento.

Se você se interessou pelo assunto, e deseja entender melhor os detalhes, recomendo que dê uma lida na documentação oficial, é o melhor local para consultas. E também, acesse o repositório que foi utilizado como exemplo para esse artigo.

À você que chegou até aqui, fica o meu agradecimento por reservar um poquinho do seu tempo para ler esse artigo. Espero que tenha aprendido um pouco mais sobre esse maravilhoso mundo mobile, sinta-se à vontade para deixar seu comentário e compartilhar esse artigo com alguém que se interesse pelo assunto também. Até a próxima! 😄 (rosto sorrindo)

Referências e recomendações de leitura

--

--

William Amaral
Android Dev BR

Software Engineer | Passionate about Technology and Philosophy