<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: João Gabriel</title>
    <description>The latest articles on DEV Community by João Gabriel (@1jgabriel).</description>
    <link>https://dev.to/1jgabriel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F393696%2F6a9fcafd-cd19-424c-95c2-ae4cbe000ef5.jpeg</url>
      <title>DEV Community: João Gabriel</title>
      <link>https://dev.to/1jgabriel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/1jgabriel"/>
    <language>en</language>
    <item>
      <title>Utilizando o Jetpack Paging v3</title>
      <dc:creator>João Gabriel</dc:creator>
      <pubDate>Thu, 16 Jul 2020 20:02:35 +0000</pubDate>
      <link>https://dev.to/1jgabriel/utilizando-o-jetpack-paging-v3-2mnd</link>
      <guid>https://dev.to/1jgabriel/utilizando-o-jetpack-paging-v3-2mnd</guid>
      <description>&lt;h2&gt;
  
  
  O que é a Paging Library?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Paging Library&lt;/strong&gt;, é uma biblioteca criada pelo &lt;strong&gt;Google&lt;/strong&gt; para resolver o problema da paginação de dados no &lt;strong&gt;Android&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Um problema que geralmente temos que resolver ao criar um aplicativo, é a solicitação de dados longos, que não exigem uma única vez, pois o usuário vê apenas uma pequena parte desses dados por vez.&lt;/p&gt;

&lt;p&gt;Uma maneira de resolver esse problema, é adicionar um &lt;em&gt;ScrollListener&lt;/em&gt; para o &lt;em&gt;RecyclerView&lt;/em&gt; e carregar mais dados quando o usuário chega ao final da lista. Com esta abordagem, é difícil manter a eficiência, também a lógica da interface do usuário e gera uma lógica de dados complicada, o que dificulta a depuração e testes do projeto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vantagens
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A &lt;strong&gt;Paging Library&lt;/strong&gt; ajuda a carregar e exibir pequenos blocos de dados por vez. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O carregamento de dados parciais sob demanda reduz o uso da largura de banda da rede e dos recursos do sistema.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Facilmente integrada ao &lt;em&gt;RecyclerView&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mantém o controle das chaves a serem usadas para recuperar a página seguinte e a anterior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Solicita automaticamente a página correta quando o usuário rola para o final da lista. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Garante que várias solicitações não sejam acionadas ao mesmo tempo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rastreia o estado de carregamento e permite exibi-lo em um &lt;em&gt;RecyclerView&lt;/em&gt; item da lista, ou em qualquer outro local da interface do usuário e mostrar facilmente as cargas com falha.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Novidades Paging 3
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Suporte interno para tratamento de erros, incluindo mecanismo de reload e retry.&lt;/li&gt;
&lt;li&gt;Suporte à &lt;em&gt;coroutines&lt;/em&gt; e &lt;em&gt;Flow&lt;/em&gt; do &lt;em&gt;Kotlin&lt;/em&gt;, assim como era ao &lt;em&gt;LiveData&lt;/em&gt; e &lt;em&gt;RxJava&lt;/em&gt; na versão 2.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Header&lt;/em&gt;, &lt;em&gt;footer&lt;/em&gt; e &lt;em&gt;separator&lt;/em&gt; incluídos na biblioteca.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Como implementar
&lt;/h2&gt;

&lt;p&gt;Primeiramente, é necessário ter o &lt;a href="https://developer.android.com/studio"&gt;Android Studio&lt;/a&gt; na versão 3.6 ou superior.&lt;/p&gt;

&lt;p&gt;Adicionar a dependência no &lt;em&gt;build.gradle&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;paging_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"3.0.0-alpha02"&lt;/span&gt;
&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"androidx.paging: paging-runtime: $ paging_version"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Até o momento da escrita deste artigo, esta é a versão atual da biblioteca&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Fluxo dos dados
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A95dnO-u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/utdrgs1ce485ib8p4jic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A95dnO-u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/utdrgs1ce485ib8p4jic.png" alt="Alt Text" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O principal componente na camada de &lt;em&gt;Repository&lt;/em&gt; é o &lt;em&gt;PagingSource&lt;/em&gt;.&lt;br&gt;
Cada objeto &lt;em&gt;PagingSource&lt;/em&gt;, define uma fonte de dados e recupera os dados dessa fonte, seja ela um banco de dados local ou uma API externa. No nosso exemplo utilizarei uma API externa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyPagingSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;api&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyApi&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PagingSource&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LoadParams&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;):&lt;/span&gt; &lt;span class="nc"&gt;LoadResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="nc"&gt;STARTING_PAGE_INDEX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;prevKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;nextKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nextPage&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="nc"&gt;STARTING_PAGE_INDEX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;LoadResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HttpException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;LoadResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;STARTING_PAGE_INDEX&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A partir da criação do nosso &lt;em&gt;PagingSource&lt;/em&gt; na camada de &lt;em&gt;Repository&lt;/em&gt;, criaremos o nosso &lt;em&gt;Pager&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;O &lt;em&gt;Pager&lt;/em&gt; é o responsável por configurar o tamanho de nossas páginas de requisição, através do &lt;em&gt;PagingConfig&lt;/em&gt;, e auxiliar no fluxo dos dados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getItems&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PagingData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Pager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PagingConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="n"&gt;pagingSourceFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;MyPagingSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cachedIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewModelScope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;A partir da Paging v3, não é necessário converter &lt;em&gt;Flow&lt;/em&gt; em &lt;em&gt;LiveData&lt;/em&gt;.&lt;br&gt;
Para manter um cache dos dados carregados no nosso &lt;em&gt;ViewModel&lt;/em&gt;, chamamos o &lt;em&gt;cachedIn&lt;/em&gt; passando o nosso &lt;em&gt;androidx.lifecycle.viewModelScope&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Agora teremos a nossa última etapa de implementação, que é  passar os dados carregados para a nossa &lt;em&gt;View&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Será necessário coletar os dados vindos do &lt;em&gt;PagingData&lt;/em&gt; e passar para o nosso &lt;em&gt;Adapter&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solicitando os dados para o &lt;em&gt;viewModel&lt;/em&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lifecycleScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItems&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;collectLatest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submitData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;A implementação do &lt;em&gt;adapter&lt;/em&gt; só precisa fazer uma extensão da classe PagingDataAdapter, e passar um &lt;em&gt;DiffUtilCallback&lt;/em&gt; para diferenciar os itens recebidos:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyAdapter&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;PagingDataAdapter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MyAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MyViewHolder&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;DiffUtilCallback&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// a implementação do corpo do adapter permanece a mesma&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DiffUtilCallBack&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DiffUtil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ItemCallback&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;areItemsTheSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;oldItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;areContentsTheSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;oldItem&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;newItem&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Esta foi a implementação necessária para fazer paginação no &lt;strong&gt;Android&lt;/strong&gt; usando a &lt;em&gt;Paging Library&lt;/em&gt;, obrigado pela leitura&lt;/p&gt;

&lt;p&gt;Todo o conteúdo foi compartilhado no meu &lt;a href="https://github.com/1jGabriel/paging-v3-sample"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vou deixar aqui links adicionais com a documentação da biblioteca:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/topic/libraries/architecture/paging/v3-overview"&gt;https://developer.android.com/topic/libraries/architecture/paging/v3-overview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codelabs.developers.google.com/codelabs/android-paging/#0"&gt;https://codelabs.developers.google.com/codelabs/android-paging/#0&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>jetpack</category>
      <category>paging</category>
    </item>
    <item>
      <title>Utilizando o Jetpack Navigation em projetos multi módulos</title>
      <dc:creator>João Gabriel</dc:creator>
      <pubDate>Sun, 07 Jun 2020 19:17:05 +0000</pubDate>
      <link>https://dev.to/1jgabriel/utilizando-o-jetpack-navigation-em-projetos-multi-modulos-4eni</link>
      <guid>https://dev.to/1jgabriel/utilizando-o-jetpack-navigation-em-projetos-multi-modulos-4eni</guid>
      <description>&lt;p&gt;Neste artigo, mostrarei como utilizar o &lt;a href="https://developer.android.com/guide/navigation" rel="noopener noreferrer"&gt;Navigation&lt;/a&gt;, em um projeto modularizado. &lt;/p&gt;

&lt;p&gt;O &lt;a href="https://developer.android.com/guide/navigation" rel="noopener noreferrer"&gt;Navigation&lt;/a&gt; é um componente que faz parte do &lt;a href="https://developer.android.com/jetpack" rel="noopener noreferrer"&gt;Jetpack&lt;/a&gt; e que consiste de três partes principais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;NavGraph&lt;/code&gt;: é um XML que centraliza as informações de navegação de uma feature.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;NavHost&lt;/code&gt;: é um contêiner vazio que mostra destinos do gráfico de navegação. O componente de navegação contém uma implementação &lt;code&gt;NavHost&lt;/code&gt; padrão, &lt;a href="https://developer.android.com/reference/androidx/navigation/fragment/NavHostFragment" rel="noopener noreferrer"&gt;&lt;code&gt;NavHostFragment&lt;/code&gt;&lt;/a&gt;, que mostra os destinos do fragment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;NavController&lt;/code&gt;: é um objeto que gerencia a navegação do aplicativo em um &lt;code&gt;NavHost&lt;/code&gt;. O &lt;code&gt;NavController&lt;/code&gt; organiza a troca do conteúdo de destino, no &lt;code&gt;NavHost&lt;/code&gt;, conforme os usuários navegam pelo aplicativo.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Texto completo &lt;a href="https://developer.android.com/guide/navigation" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Porque utilizar o  &lt;a href="https://developer.android.com/guide/navigation" rel="noopener noreferrer"&gt;Navigation&lt;/a&gt;?
&lt;/h2&gt;

&lt;p&gt;Com o  &lt;a href="https://developer.android.com/guide/navigation" rel="noopener noreferrer"&gt;Navigation&lt;/a&gt;  é possível ver toda a navegação através do &lt;code&gt;NavGraph&lt;/code&gt;, não sendo necessário procurar por cada &lt;code&gt;Intent&lt;/code&gt; e &lt;code&gt;FragmentTransaction&lt;/code&gt; no projeto. Além disso, ele permite encontrar todos os destinos possíveis.&lt;/p&gt;

&lt;p&gt;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 &lt;strong&gt;deep link&lt;/strong&gt;. Em relação ao &lt;strong&gt;deep link&lt;/strong&gt;, vale salientar que ele também tem essa informação da navegação.&lt;/p&gt;

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

&lt;p&gt;Ele também funciona com os padrões atuais da &lt;strong&gt;interface do usuário de navegação,&lt;/strong&gt; como &lt;a href="https://material.io/components/bottom-navigation" rel="noopener noreferrer"&gt;bottom-navigation&lt;/a&gt;, com apenas algumas configurações.&lt;br&gt;
É possível também criar transições e animações 💙 entre a navegação. &lt;/p&gt;
&lt;h2&gt;
  
  
  Pré requisitos
&lt;/h2&gt;

&lt;p&gt;Para utilizar o &lt;a href="https://developer.android.com/guide/navigation" rel="noopener noreferrer"&gt;Navigation&lt;/a&gt; é necessário ter instalado o &lt;a href="https://developer.android.com/studio/" rel="noopener noreferrer"&gt;Android Studio&lt;/a&gt; na versão 3.3 ou superior.&lt;/p&gt;

&lt;p&gt;E adicionar no &lt;em&gt;build.gradle&lt;/em&gt; do projeto as dependências do navigation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;  &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"androidx.navigation:navigation-fragment-ktx:2.2.2"&lt;/span&gt;
  &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"androidx.navigation:navigation-ui-ktx:2.2.2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;No momento da criação deste artigo a versão mais recente é a 2.2.2.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hands On
&lt;/h2&gt;

&lt;p&gt;Como exemplo, temos uma feature 1 que tem 2 fragments e faz a navegação de &lt;em&gt;Fragment A -&amp;gt; Fragment B&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5kkj7pp00gtdotr2zavu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5kkj7pp00gtdotr2zavu.png" alt="Feature 1 exemplo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Utilizando o navigation, precisaremos apenas de um &lt;code&gt;NavGraph&lt;/code&gt;com nossos 2 destinos e um action que leva do &lt;code&gt;Fragment A&lt;/code&gt; ao &lt;code&gt;Fragment B&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkgofl8epd7kakqdjqhob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkgofl8epd7kakqdjqhob.png" alt="Nav Graph Feature 1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;navigation&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:app=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:tools=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/tools"&lt;/span&gt;
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/nav_feature_one"&lt;/span&gt;
    &lt;span class="na"&gt;app:startDestination=&lt;/span&gt;&lt;span class="s"&gt;"@id/fragment_a"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_a"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"io.jgabriel.featureone.FragmentA"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt;
            &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/navigate_to_b"&lt;/span&gt;
            &lt;span class="na"&gt;app:destination=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_b"&lt;/span&gt;
            &lt;span class="na"&gt;app:popUpTo=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_a"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fragment&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_b"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"io.jgabriel.featureone.FragmentB"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/navigation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Assim, temos a navegação da nossa primeira feature.&lt;/p&gt;



&lt;p&gt;Agora iremos aumentar a nossa aplição incluindo mais 2 feature modules :&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1r41qrrroiwp164xjjp2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1r41qrrroiwp164xjjp2.png" alt="Project Tree"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dessa maneira, nossa aplicação conterá essas features e fragments:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffdvrhjg3ug6pw41tyz23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffdvrhjg3ug6pw41tyz23.png" alt="All Features"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Será necessário também adicionar os &lt;code&gt;NavGraphs&lt;/code&gt;para as novas features, criadas seguindo o mesmo modelo da Feature 1&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm5jfulme553emi4rqvu8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm5jfulme553emi4rqvu8.png" alt="Feature two nav graph"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;navigation&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:app=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:tools=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/tools"&lt;/span&gt;
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/nav_feature_two"&lt;/span&gt;
    &lt;span class="na"&gt;app:startDestination=&lt;/span&gt;&lt;span class="s"&gt;"@id/fragment_c"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_c"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"io.jgabriel.featuretwo.FragmentC"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt;
            &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/navigate_to_d"&lt;/span&gt;
            &lt;span class="na"&gt;app:destination=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_d"&lt;/span&gt;
            &lt;span class="na"&gt;app:popUpTo=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_c"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fragment&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_d"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"io.jgabriel.featuretwo.FragmentD"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/navigation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnuedswjm34lg9u6vgw4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnuedswjm34lg9u6vgw4w.png" alt="Feature two nav graph"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;navigation&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:app=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:tools=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/tools"&lt;/span&gt;
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/nav_feature_three"&lt;/span&gt;
    &lt;span class="na"&gt;app:startDestination=&lt;/span&gt;&lt;span class="s"&gt;"@id/fragment_e"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_e"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"io.jgabriel.featurethree.FragmentE"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt;
            &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/navigate_to_"&lt;/span&gt;
            &lt;span class="na"&gt;app:destination=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_f"&lt;/span&gt;
            &lt;span class="na"&gt;app:popUpTo=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_e"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fragment&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_f"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"io.jgabriel.featurethree.FragmentF"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/navigation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Precisamos adicionar as nossas feature ao módulo de aplicação através do &lt;em&gt;build.gradle&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjspp3rityxrkjk397l5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjspp3rityxrkjk397l5j.png" alt="Module app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;project&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":featureone"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;project&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":featuretwo"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;project&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":featurethree"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Agora o nosso módulo de aplicação conhece as nossas 3 features.&lt;/p&gt;



&lt;p&gt;Para não precisar repetir toda a navegação feita em cada feature, vamos reutilizar os &lt;em&gt;NavGraphs&lt;/em&gt;, através da tag de &lt;em&gt;include&lt;/em&gt; dentro do &lt;em&gt;NavGraph&lt;/em&gt; do nosso módulo e aplicação&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;navigation&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:app=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/nav_main"&lt;/span&gt;
    &lt;span class="na"&gt;app:startDestination=&lt;/span&gt;&lt;span class="s"&gt;"@id/nav_feature_one"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;include&lt;/span&gt; &lt;span class="na"&gt;app:graph=&lt;/span&gt;&lt;span class="s"&gt;"@navigation/nav_feature_one"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;include&lt;/span&gt; &lt;span class="na"&gt;app:graph=&lt;/span&gt;&lt;span class="s"&gt;"@navigation/nav_feature_two"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;include&lt;/span&gt; &lt;span class="na"&gt;app:graph=&lt;/span&gt;&lt;span class="s"&gt;"@navigation/nav_feature_three"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/navigation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Agora é possível fazer a navegação de qualquer fragment dentro do módulo de aplicação.&lt;/p&gt;



&lt;p&gt;Em problemas reais, geralmente precisamos acessar um fragment de uma feature, através de outra, por exemplo:&lt;/p&gt;

&lt;p&gt;O Fragment B, que está na Feature 1, precisa navegar até o Fragment D, que está na  Feature 2: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc2mkyvg1f79bmh6nb1n1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc2mkyvg1f79bmh6nb1n1.png" alt="Navigate fragment b to d"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;
  
  
  NavGraph Feature Two
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;navigation&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:app=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res-auto"&lt;/span&gt;
    &lt;span class="na"&gt;xmlns:tools=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/tools"&lt;/span&gt;
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/nav_feature_two"&lt;/span&gt;
    &lt;span class="na"&gt;app:startDestination=&lt;/span&gt;&lt;span class="s"&gt;"@id/fragment_c"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_c"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"io.jgabriel.featuretwo.FragmentC"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt;
            &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/navigate_to_d"&lt;/span&gt;
            &lt;span class="na"&gt;app:destination=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_d"&lt;/span&gt;
            &lt;span class="na"&gt;app:popUpTo=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_c"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fragment&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fragment&lt;/span&gt;
        &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_d"&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"io.jgabriel.featuretwo.FragmentD"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;deepLink&lt;/span&gt; &lt;span class="na"&gt;app:uri=&lt;/span&gt;&lt;span class="s"&gt;"navApp://fragmentD"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fragment&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/navigation&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Utilizando a tag &lt;code&gt;deepLink&lt;/code&gt;, podemos especificar o URI que podemos usar para navegar para esse destino específico, sem a &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Feature One&lt;/em&gt; precisar conhecer a nossa &lt;em&gt;Feature Two&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Para fazer essa navegação, vamos adicionar um click no FragmentB que vai navegar até o FragmentD&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FragmentB&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onViewCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;uri&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"navApp://fragmentD"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;findNavController&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Dessa forma, mantemos os nossos módulos independentes um dos outros, e capazes de navegarem entre si.&lt;/p&gt;



&lt;p&gt;Obrigado por ler até aqui. Todo o código utilizado está disponível em:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/1jGabriel" rel="noopener noreferrer"&gt;
        1jGabriel
      &lt;/a&gt; / &lt;a href="https://github.com/1jGabriel/Navigation-multi-module" rel="noopener noreferrer"&gt;
        Navigation-multi-module
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Navegação utilizando deeplink em um projeto modularizado
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>android</category>
      <category>kotlin</category>
      <category>navigation</category>
      <category>jetpack</category>
    </item>
    <item>
      <title>Utilizando MergeAdapter no Android</title>
      <dc:creator>João Gabriel</dc:creator>
      <pubDate>Sat, 23 May 2020 21:37:18 +0000</pubDate>
      <link>https://dev.to/1jgabriel/utilizando-mergeadapter-no-android-5476</link>
      <guid>https://dev.to/1jgabriel/utilizando-mergeadapter-no-android-5476</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;MergeAdapter é uma nova feature introduzida no &lt;a href="https://developer.android.com/jetpack/androidx/releases/recyclerview"&gt;recyclerview:1.2.0-alpha02&lt;/a&gt;, habilitando a possibilidade de agrupar adapters e os exibir sequencialmente utilizando o mesmo &lt;code&gt;RecyclerView&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integração
&lt;/h2&gt;

&lt;p&gt;Para fazer o uso do &lt;a href="https://developer.android.com/reference/androidx/recyclerview/widget/MergeAdapter"&gt;Merge Adapter&lt;/a&gt; é necessário adicionar a dependência no &lt;code&gt;build.gradle&lt;/code&gt; do app ou módulo que irá fazer a utilização:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dependencies {&lt;br&gt;
      implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha03'&lt;br&gt;
}&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
  &lt;em&gt;até o momento deste texto, esta era a versão mais recente da biblioteca.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Hands On
&lt;/h2&gt;

&lt;p&gt;Será utilizado o &lt;a href="https://beta.playvalorant.com/pt-br/"&gt;Valorant&lt;/a&gt;, jogo recém lançado pela &lt;a href="https://www.riotgames.com/en"&gt;Riot Games&lt;/a&gt;, como exemplo.&lt;/p&gt;

&lt;p&gt;Neste exemplo, serão utilizados: um layout de header, uma lista de personagens e um banner, assim criando um adapter para cada view: &lt;code&gt;HeaderAdapter&lt;/code&gt;, &lt;code&gt;PersonageAdapter&lt;/code&gt; e &lt;code&gt;BannerAdapter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Será necessário fazer o merge dos 3 adapters, utilizando o construtor do &lt;a href="https://developer.android.com/reference/androidx/recyclerview/widget/MergeAdapter"&gt;Merge Adapter&lt;/a&gt; e passando sua instância para o adapter do &lt;code&gt;recyclerview&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;val headerAdapter: HeaderAdapter= …&lt;br&gt;
val personageAdapter: PersonageAdapter= …&lt;br&gt;
val bannerAdapter: BannerAdapter= …&lt;br&gt;
val mergeAdapter = MergeAdapter(headerAdapter, personageAdapter, &lt;br&gt;
     footerAdapter)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;As views do &lt;code&gt;recyclerview&lt;/code&gt;, serão renderizadas de acordo com a ordem dos adapters passados no construtor do [Merge Adapter] .(&lt;a href="https://developer.android.com/reference/androidx/recyclerview/widget/MergeAdapter"&gt;https://developer.android.com/reference/androidx/recyclerview/widget/MergeAdapter&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;recyclerView.adapter = mergeAdapter&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Obtendo o seguinte resultado: &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S1Aw_l4x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/pisbz5l2qa5wdcujsvjc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S1Aw_l4x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/pisbz5l2qa5wdcujsvjc.png" alt="RecyclerView Completo" width="800" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Toda a implementação dos adapters, e dados utilizados estão disponíveis em: &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9-wwsHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/1jGabriel"&gt;
        1jGabriel
      &lt;/a&gt; / &lt;a href="https://github.com/1jGabriel/Valorant-Merge-Adapter"&gt;
        Valorant-Merge-Adapter
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Repositório para testes do merge adapter
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Dica ao utilizar &lt;a href="https://developer.android.com/reference/androidx/recyclerview/widget/MergeAdapter"&gt;Merge Adapter&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;É recomendável também utilizar que cada adapter faça a extensão de &lt;code&gt;ListAdapters&lt;/code&gt; para evitar chamar &lt;code&gt;RecyclerView.Adapter.notifyDataSetChanged()&lt;/code&gt; assim ao passar novos dados para um adapter só é necessário chamar &lt;code&gt;adapter.submitList(list)&lt;/code&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
    </item>
  </channel>
</rss>
