Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to refresh recyclerview using MVP Structure in android?

I want simple example for MVP structure in android to refresh recyclerview item not the whole list of recyclerview.

It will refresh only items in recyclerview of android.

like image 785
BK19 Avatar asked Jul 29 '16 10:07

BK19


1 Answers

This is a problem I've thought about quite a lot. There are two possible ways of doing it:

  • Pass the new List of data to the Adapter and it does the work of working out what's changed and updating the correct items.
  • Keep a record of the current items in your model then when the new list is calculated send ListChangeItems to the Adapter.

I'll outline both in more detail below. In both cases you need to calculate the differences between what is currently showing and the new data. I have a helper class ListDiffHelper<T> which does this comparison:

public class ListDiffHelper<T> {

    private List<T> oldList;
    private List<T> newList;

    private List<Integer> inserted = new ArrayList<>();
    private List<Integer> removed = new ArrayList<>();

    public List<Integer> getInserted() {return inserted;}
    public List<Integer> getRemoved() {return removed;}

    public ListDiffHelper(List<T> oldList, List<T> newList) {

        this.oldList = oldList;
        this.newList = newList;

        checkForNull();

        findInserted();
        findRemoved();
    }

    private void checkForNull() {

        if (oldList == null) oldList = Collections.emptyList();
        if (newList == null) newList = Collections.emptyList();
    }

    private void findInserted() {

        Set<T> newSet = new HashSet<>(newList);
        newSet.removeAll(new HashSet<>(oldList));

        for (T item : newSet) {
            inserted.add(newList.indexOf(item));
        }

        Collections.sort(inserted, new Comparator<Integer>() {
            @Override
            public int compare(Integer lhs, Integer rhs) {
                return lhs - rhs;
            }
        });
    }

    private void findRemoved() {

        Set<T> oldSet = new HashSet<>(oldList);
        oldSet.removeAll(new HashSet<>(newList));

        for (T item : oldSet) {
            removed.add(oldList.indexOf(item));
        }

        Collections.sort(inserted, new Comparator<Integer>() {
            @Override
            public int compare(Integer lhs, Integer rhs) {
                return rhs - lhs;
            }
        });
    }
}

For this to work properly you need to ensure that the equals() method of the Data class compares things in a suitable way.

Adapter Lead

In this case your Presenter calls getData() on the model (or subscribes to it if you're using Rx) and receives List<Data>. It then passes this List to the view through a setData(data) method which in turn give the list to the Adapter. The method in the Adapter would look something like:

private void setData(List<Data> data) {

    if (this.data == null || this.data.isEmpty() || data.isEmpty()) {
        this.data = data;
        adapter.notifyDataSetChanged();
        return;
    }

    ListDiffHelper<Data> diff = new ListDiffHelper<>(this.data, data);
    this.data = data;

    for (Integer index : diff.getRemoved()) {
       notifyItemRemoved(index);
    }
    for (Integer index : diff.getInserted()) {
       notifyItemInserted(index);
    }
}

It is important to remove items first before adding new ones otherwise the order will not be maintained correctly.

Model Lead

The alternative approach is to keep the Adapter much dumber and do the calculation of what has changed in your model layer. You then need a wrapper class to send the individual changes to your View/Adapter. Something like:

public class ListChangeItem {

    private static final int INSERTED = 0;
    private static final int REMOVED = 1;

    private int type;
    private int position;
    private Data data;

    public ListChangeItem(int type, int position, Data data) {
        this.type = type;
        this.position = position;
        this.data = data;
    }

    public int getType() {return type;}
    public int getPosition() {return position;}
    public Data getData() {return data;}
}

You would then pass a List of these to your Adapter via the view interface. Again it would be important to have the removals actioned before the inserts to ensure the data is in the correct order.

like image 200
Jahnold Avatar answered Nov 14 '22 20:11

Jahnold