Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView using DiffUtil, prevent to scroll bottom on change

I have a problem with my recyclerViev, specifically with the scrolling. I have some list, which is updated in real time, some item is added, some removed, and everything is sorted by some parameter. So the item which was initially first on the list, can have its parameter changed, which will be in different position after the sorting.

So my recyclerView is for example focusing on the initial item, and after change, when some item has "better" parameter is changing position with that initial item.

Problem is, i want to focus on the new item, with "better" parameter when I'm not scrolling, but i don't want to focusing on it when i scroll by touch(so my touch will not be interrupted by scrolling to current first item on the list).

So i don't want to force this code after every change in my recyclerView data:

recyclerView.scrollToPosition(0);

because as i said, i will be interrupted by this scroll when i am touching my recyclerView list and go down to see other items and in the same time there will be a change in my list.

Is there a way to accomplish this?

To be specific, i am using DiffCallback from the DiffUtil, to support animations when there is a change in my current recyclerView list - it compares the old list with another new list and apply all the wanted animations and notifications(item added, removed, changed position). So i never call

notifyDataSetChanged

or anything like that

Here is my DiffUtil callback:

  public static class DevicesDiffCallback extends DiffUtil.Callback{

    List<DeviceInfo> oldDevices;
    List<DeviceInfo> newDevices;

    public DevicesDiffCallback(List<NexoDeviceInfo> newDevices, List<NexoDeviceInfo> oldDevices) {
        this.newDevices = newDevices;
        this.oldDevices = oldDevices;
    }

    @Override
    public int getOldListSize() {
        return oldDevices != null ? oldDevices.size() : 0;
    }

    @Override
    public int getNewListSize() {
        return newDevices != null ?  newDevices.size() : 0;
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldDevices.get(oldItemPosition).getNexoIdentifier().getSerialNumber().equals(newDevices.get(newItemPosition).getNexoIdentifier().getSerialNumber());
    }

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

    @Override
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {
        return super.getChangePayload(oldItemPosition, newItemPosition);
    }
}

And i set it like this in my adapter, when i get the list of new data to be populated and replace the old data:

 public void setData(List<DeviceInfo> data) {
    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DevicesDiffCallback(this.mData, data), false);
    diffResult.dispatchUpdatesTo(this);

        mData = data;

}
like image 677
K.Os Avatar asked Dec 04 '17 11:12

K.Os


1 Answers

I'm not sure about this answer but, I think your code to call DiffUtil is not proper. Try using this :

public void addItems(List<Recipe> recipeList) {

    List<Recipe> newRecipeList = new ArrayList<>();
    newRecipeList.addAll(this.recipeList);
    newRecipeList.addAll(recipeList);

    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new RecipeDiffUtilCallback(this.recipeList, newRecipeList));
    this.recipeList.addAll(recipeList);
    diffResult.dispatchUpdatesTo(this);
}
like image 80
Vicky Avatar answered Nov 01 '22 00:11

Vicky