Neste artigo, mostrarei como utilizar o Navigation, em um projeto modularizado.
O Navigation é um componente que faz parte do 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çãoNavHost
padrão,NavHostFragment
, que mostra os destinos do fragment.NavController
: é um objeto que gerencia a navegação do aplicativo em umNavHost
. ONavController
organiza a troca do conteúdo de destino, noNavHost
, conforme os usuários navegam pelo aplicativo.
Texto completo aqui.
Porque utilizar o Navigation?
Com o 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, com apenas algumas configurações.
É possível também criar transições e animações 💙 entre a navegação.
Pré requisitos
Para utilizar o Navigation é necessário ter instalado o Android Studio na versão 3.3 ou superior.
E adicionar no build.gradle do projeto as dependências do navigation:
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
Utilizando o navigation, precisaremos apenas de um NavGraph
com nossos 2 destinos e um action que leva do Fragment A
ao Fragment B
<?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>
Assim, temos a navegação da nossa primeira feature.
Agora iremos aumentar a nossa aplição incluindo mais 2 feature modules :
Dessa maneira, nossa aplicação conterá essas features e fragments:
Será necessário também adicionar os NavGraphs
para as novas features, criadas seguindo o mesmo modelo da Feature 1
<?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>
<?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>
Precisamos adicionar as nossas feature ao módulo de aplicação através do build.gradle
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 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:
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 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
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:
Top comments (0)