Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DiffUtil

 DiffUtil

Apresentada no Android BH - S02E03!

Jean Pimentel

March 21, 2017
Tweet

More Decks by Jean Pimentel

Other Decks in Technology

Transcript

  1. 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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. 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.

    View full-size slide

  6. 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.

    View full-size slide

  7. 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);

    View full-size slide

  8. 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;
    }

    View full-size slide

  9. 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();
    }

    View full-size slide

  10. }
    @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));
    }

    View full-size slide

  11. @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;
    }

    View full-size slide

  12. 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 */
    }

    View full-size slide

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

    View full-size slide

  14. 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.

    View full-size slide

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

    View full-size slide