How to update RecyclerView simply and efficiently?

4

The ways I know to update a RecyclerView most efficiently is to use adapter methods

  • notifyItemMoved
  • notifyItemRangeChanged
  • notifyItemRangeInserted
  • notifyItemRangeRemoved

They, unlike notifyDataSetChanged() , only cause refresh of the visible items they refer to (those that have been moved / changed / inserted / removed), and therefore more efficient .

Its use is simple when changes are made "in turn", just call the method corresponding to the change made. The difficulty arises when several changes are made at once, for example, when a new, updated list comes from a call to a service, which leads me to use notifyDataSetChanged() .

In the latter case, how can I update using methods notifyItemXXX() ?

    
asked by anonymous 18.01.2017 / 00:08

1 answer

4

In the Support Library revision 24.2.0, one of updates was the addition of the class DiffUtil . > It makes it possible to calculate the difference between two collections and get an object of type DiffUtil.DiffResult that contains a list of update operations to apply to a RecyclerView.Adapter.

Operations are applied using the DiffResult # dispatchUpdatesTo () that internally uses notifyItemXXX() methods to notify adapter.

DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(callback); 
diffResult.dispatchUpdatesTo(adapter);

DiffUtil needs to get some information about the old and new collection, such as size and how to compare items. This information is obtained using the DiffUtil.Callback passed to method DiffUtil.calculateDiff () .
The implementation of callback depends on the type the collection holds.

Implementation example:

public class ProdutoDiffCallback extends DiffUtil.Callback{

    List<Produto> oldProdutos;
    List<Produto> newProdutos;

    public ProdutoDiffCallback(List<Produto> newProdutos, List<Produto> oldProdutos) {
        this.newProdutos = newProdutos;
        this.oldProdutos = oldProdutos;
    }

    @Override
    public int getOldListSize() {
        return oldProdutos.size();
    }

    @Override
    public int getNewListSize() {
        return newProdutos.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldProdutos.get(oldItemPosition).id == newProdutos.get(newItemPosition).id;
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return oldProdutos.get(oldItemPosition).equals(newProdutos.get(newItemPosition));
    }

}

The RecyclerView update can be implemented in an Adapter method as follows:

public void updateList(ArrayList<Produto> newProdutos) {
    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new ProdutoDiffCallback(this.Produtos, newProduto));
    this.Produtos = newProdutos
    diffResult.dispatchUpdatesTo(this);
}
    
18.01.2017 / 00:09