How to update Recyclerview simply and efficiently?

Asked

Viewed 1,577 times

4

The most efficient way I know to update a Recyclerview is to resort to Adapter methods

  • notifyItemMoved
  • notifyItemRangeChanged
  • notifyItemRangeInserted
  • notifyItemRangeRemoved

They, as opposed to notifyDataSetChanged(), only provoke the refresh of the visible items to which they refer (those that have been moved/changed/inserted/removed), and are 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 you receive a new list, updated, from a call to a service, which leads me to use notifyDataSetChanged().

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

1 answer

4

In Support Library Review 24.2.0, one of the updates was the addition of the class Diffutil.
It makes it possible to calculate the difference between two collections and obtain an object of the type Diffutil.Diffresult which contains a list of upgrade operations to be applied to a Recyclerview.Adapter.

Operations shall be implemented using the Diffresult#dispatchUpdatesTo() that internally uses the methods notifyItemXXX() to notify the 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 Diffutil.Callback passed to the method Diffutil.calculateDiff().
The implementation of callback depends on the type the collection holds.

Example of implementation:

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 upgrade 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);
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.