Utilizando o Jetpack Navigation em projetos multi módulos
Tags: android, kotlin, navigation, jetpack
Published: 2020-06-07 19:17:05



Neste artigo, mostrarei como utilizar o [Navigation](https://developer.android.com/guide/navigation), em um projeto modularizado. 

O [Navigation](https://developer.android.com/guide/navigation) é um componente que faz parte do [Jetpack](https://developer.android.com/jetpack) e que consiste de três partes principais:

- `NavGraph`: é um XML que centraliza as informações de navegação de uma feature.

- `NavHost`: é um contêiner vazio que mostra destinos do gráfico de navegação. O componente de navegação contém uma implementação `NavHost` padrão, [`NavHostFragment`](https://developer.android.com/reference/androidx/navigation/fragment/NavHostFragment), que mostra os destinos do fragment.

- `NavController`: é um objeto que gerencia a navegação do aplicativo em um `NavHost`. O `NavController` organiza a troca do conteúdo de destino, no `NavHost`, conforme os usuários navegam pelo aplicativo.

  Texto completo [aqui](https://developer.android.com/guide/navigation).

  

## Porque utilizar o  [Navigation](https://developer.android.com/guide/navigation)?

Com o  [Navigation](https://developer.android.com/guide/navigation)  é possível ver toda a navegação através do `NavGraph`, não sendo necessário procurar por cada `Intent` e `FragmentTransaction` no projeto. Além disso, ele permite encontrar todos os destinos possíveis.

Um outro ponto positivo, é que não é mais necessário se preocupar com o fato do botão "voltar" sair do aplicativo ao vir de um **deep link**. Em relação ao **deep link**, vale salientar que ele também tem essa informação da navegação.

**Segurança ao passar argumentos utilizando o SafeArgs**. Não é mais necessário fazer verificações e proteções de segurança, porque é possível ter os argumentos com tipos definidos.

Ele também funciona com os padrões atuais da **interface do usuário de navegação,** como [bottom-navigation] (https://material.io/components/bottom-navigation), com apenas algumas configurações.
É possível também criar transições e animações :blue_heart: entre a navegação. 



## Pré requisitos

Para utilizar o [Navigation](https://developer.android.com/guide/navigation) é necessário ter instalado o [Android Studio](https://developer.android.com/studio/) na versão 3.3 ou superior.

E adicionar no *build.gradle* do projeto as dependências do navigation:

```groovy
  implementation "androidx.navigation:navigation-fragment-ktx:2.2.2"
  implementation "androidx.navigation:navigation-ui-ktx:2.2.2"
```

*No momento da criação deste artigo a versão mais recente é a 2.2.2.*

Em projetos monolitos, temos todas as features e camadas em um único módulo, mas nem todas features precisam uma das outras, isso também se aplica a navegação.

## Hands On

Como exemplo, temos uma feature 1 que tem 2 fragments e faz a navegação de *Fragment A -> Fragment B*

![Feature 1 exemplo](https://dev-to-uploads.s3.amazonaws.com/i/5kkj7pp00gtdotr2zavu.png)

Utilizando o navigation, precisaremos apenas de um `NavGraph`com nossos 2 destinos e um action que leva do `Fragment A` ao `Fragment B`

![Nav Graph Feature 1](https://dev-to-uploads.s3.amazonaws.com/i/kgofl8epd7kakqdjqhob.png)



```xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_feature_one"
    app:startDestination="@id/fragment_a">

    <fragment
        android:id="@+id/fragment_a"
        android:name="io.jgabriel.featureone.FragmentA">

        <action
            android:id="@+id/navigate_to_b"
            app:destination="@+id/fragment_b"
            app:popUpTo="@+id/fragment_a" />
    </fragment>
    <fragment
        android:id="@+id/fragment_b"
        android:name="io.jgabriel.featureone.FragmentB"/>

</navigation>
```
[^NavGraph  da Feature 1]: `NavGraph`da Feature 1

Assim, temos a navegação da nossa primeira feature.

------

Agora iremos aumentar a nossa aplição incluindo mais 2 feature modules :
![Project Tree](https://dev-to-uploads.s3.amazonaws.com/i/1r41qrrroiwp164xjjp2.png)

Dessa maneira, nossa aplicação conterá essas features e fragments:

![All Features](https://dev-to-uploads.s3.amazonaws.com/i/fdvrhjg3ug6pw41tyz23.png)


Será necessário também adicionar os `NavGraphs`para as novas features, criadas seguindo o mesmo modelo da Feature 1

![Feature two nav graph](https://dev-to-uploads.s3.amazonaws.com/i/m5jfulme553emi4rqvu8.png)

```xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_feature_two"
    app:startDestination="@id/fragment_c">

    <fragment
        android:id="@+id/fragment_c"
        android:name="io.jgabriel.featuretwo.FragmentC">

        <action
            android:id="@+id/navigate_to_d"
            app:destination="@+id/fragment_d"
            app:popUpTo="@+id/fragment_c" />
    </fragment>
    <fragment
        android:id="@+id/fragment_d"
        android:name="io.jgabriel.featuretwo.FragmentD"/>

</navigation>
```
[^NavGraph Feature 2]: `NavGraph`Feature 2

![Feature two nav graph](https://dev-to-uploads.s3.amazonaws.com/i/nuedswjm34lg9u6vgw4w.png)

```xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_feature_three"
    app:startDestination="@id/fragment_e">

    <fragment
        android:id="@+id/fragment_e"
        android:name="io.jgabriel.featurethree.FragmentE">

        <action
            android:id="@+id/navigate_to_"
            app:destination="@+id/fragment_f"
            app:popUpTo="@+id/fragment_e" />
    </fragment>
    <fragment
        android:id="@+id/fragment_f"
        android:name="io.jgabriel.featurethree.FragmentF" />
</navigation>
```
[^NavGraph feature 3]: NavGraph Feature 3

Precisamos adicionar as nossas feature ao módulo de aplicação através do *build.gradle*

![Module app](https://dev-to-uploads.s3.amazonaws.com/i/jspp3rityxrkjk397l5j.png)

​
```groovy
implementation project(":featureone")
implementation project(":featuretwo")
implementation project(":featurethree")
```

Agora o nosso módulo de aplicação conhece as nossas 3 features.

------

Para não precisar repetir toda a navegação feita em cada feature, vamos reutilizar os *NavGraphs*, através da tag de *include* dentro do *NavGraph* do nosso módulo e aplicação

```xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_main"
    app:startDestination="@id/nav_feature_one">

    <include app:graph="@navigation/nav_feature_one" />
    <include app:graph="@navigation/nav_feature_two" />
    <include app:graph="@navigation/nav_feature_three" />
</navigation>
```

Agora é possível fazer a navegação de qualquer fragment dentro do módulo de aplicação.

------

Em problemas reais, geralmente precisamos acessar um fragment de uma feature, através de outra, por exemplo:

O Fragment B, que está na Feature 1, precisa navegar até o Fragment D, que está na  Feature 2: 

![Navigate fragment b to d](https://dev-to-uploads.s3.amazonaws.com/i/c2mkyvg1f79bmh6nb1n1.png)

Para isso vamos adicionar deep links aos fragments e fazer a navegação através deles. Assim, as features continuarão independentes e o módulo de app será o responsável por gerenciar essa navegação.

### NavGraph Feature Two

```xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_feature_two"
    app:startDestination="@id/fragment_c">

    <fragment
        android:id="@+id/fragment_c"
        android:name="io.jgabriel.featuretwo.FragmentC">

        <action
            android:id="@+id/navigate_to_d"
            app:destination="@+id/fragment_d"
            app:popUpTo="@+id/fragment_c" />
    </fragment>
    <fragment
        android:id="@+id/fragment_d"
        android:name="io.jgabriel.featuretwo.FragmentD">
        <deepLink app:uri="navApp://fragmentD" />
    </fragment>

</navigation>
```

Utilizando a tag `deepLink`, podemos especificar o URI que podemos usar para navegar para esse destino específico, sem a 

*Feature One* precisar conhecer a nossa *Feature Two*. 

Para fazer essa navegação, vamos adicionar um click no FragmentB que vai navegar até o FragmentD

```kotlin
class FragmentB : Fragment() {
    fun onViewCreated(...) {
        ...
        ...
        view.setOnClickListener { 
            val uri = Uri.parse("navApp://fragmentD")
            findNavController().navigate(uri)
        }
   }
}
```

Dessa forma, mantemos os nossos módulos independentes um dos outros, e capazes de navegarem entre si.

------

Obrigado por ler até aqui. Todo o código utilizado está disponível em:

{% github 1jGabriel/Navigation-multi-module no-readme %}