Slide 1

Slide 1 text

DiffUtil

Slide 2

Slide 2 text

Jean Pimentel Product Engineer na CI&T Desenvolvedor mobile há 3 anos Leitor de ficção científica Co-organizador do Android BH e CocoaHeads BH

Slide 3

Slide 3 text

Listas - RecyclerViews Algumas listas são constantemente atualizadas por diversos motivos: geolocalização, ordenação, uso de filtros, dados em tempo real etc.

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Listas - RecyclerViews Passamos a nova lista para o Adapter e geralmente chamamos notifyDataSetChanged().

Slide 6

Slide 6 text

Listas - RecyclerViews Passamos a nova lista para o Adapter e geralmente chamamos notifyDataSetChanged(). Atenção! Operação custosa!

Slide 7

Slide 7 text

Listas - RecyclerViews notifyDataSetChanged() invalidará todos os dados e todas as views "visíveis" serão destruídas e recriadas. Há quem também recrie o Adapter nesses casos, mas isso é ainda mais custoso.

Slide 8

Slide 8 text

DiffUtil Classe auxiliar contida na support-v7 que calcula a diferença entre duas listas e retorna uma lista de operações a serem feitas para essa conversão.

Slide 9

Slide 9 text

DiffUtil.Callback ● Necessário estender DiffUtil.Callback e implementar os métodos: int getOldListSize(); int getNewListSize(); boolean areItemsTheSame(int oldItemPosition, int newItemPosition); boolean areContentsTheSame(int oldItemPosition, int newItemPosition); Object getChangePayload(int oldItemPosition, int newItemPosition);

Slide 10

Slide 10 text

import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.util.DiffUtil; import java.util.List; public class PlacesDiffCallback extends DiffUtil.Callback { private List oldItems; private List newItems; public PlacesDiffCallback(List oldItems, List newItems) { this.oldItems = oldItems; this.newItems = newItems; }

Slide 11

Slide 11 text

public class PlacesDiffCallback extends DiffUtil.Callback { private List oldItems; private List newItems; public PlacesDiffCallback(List oldItems, List newItems) { this.oldItems = oldItems; this.newItems = newItems; } @Override public int getOldListSize() { return oldItems.size(); } @Override public int getNewListSize() { return newItems.size(); }

Slide 12

Slide 12 text

} @Override public int getOldListSize() { return oldItems.size(); } @Override public int getNewListSize() { return newItems.size(); } @Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { return newItems.get(newItemPosition).getId() == oldItems.get(oldItemPosition).getId(); } @Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { return newItems.get(newItemPosition).equals(oldItems.get(oldItemPosition)); }

Slide 13

Slide 13 text

@Nullable @Override public Object getChangePayload(int oldItemPosition, int newItemPosition) { Place newPlace = newItems.get(newItemPosition); Place oldPlace = oldItems.get(oldItemPosition); Bundle diffBundle = new Bundle(); if (newPlace.getDistance() != oldPlace.getDistance()) { diffBundle.putInt(Place.KEY_DISTANCE, newPlace.getDistance()); } if (!newPlace.getPrice().equals(oldPlace.getPrice())) { diffBundle.putString(Place.KEY_PRICE, newPlace.getPrice()); } if (!newPlace.getWaitingTime().equals(oldPlace.getWaitingTime())) { diffBundle.putString(Place.KEY_WAITING_TIME, newPlace.getWaitingTime()); } if (newPlace.hasFreeDelivery() != oldPlace.hasFreeDelivery()) { diffBundle.putBoolean(Place.KEY_FREE_DELIVERY, newPlace.hasFreeDelivery()); } return diffBundle.size() == 0 ? null : diffBundle; }

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

DiffUtil + DiffUtil.Callback Utilizando: public void onListChanged(List newPlaces) { PlacesDiffCallback callback = new PlacesDiffCallback(places, newPlaces); DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(callback); places = newPlaces; diffResult.dispatchUpdatesTo(this); /* adapter */ }

Slide 16

Slide 16 text

Considerações Não bloqueie sua UI. Obtenha o DiffResult em background e aplique na mainThread.

Slide 17

Slide 17 text

Considerações ● O DiffUtil utiliza o algoritmo de Eugene Myers, de complexidade O(n). ● No entanto, se houver movimentação de itens, a complexidade é aumentada em O(n2), onde n = número de elementos adicionados e removidos. ● Se suas listas são ordenadas pelo mesmo critério, desabilite a detecção de movimento.

Slide 18

Slide 18 text

Contato [email protected] speakerdeck.com/jeanpimentel github.com/jeanpimentel