RecyclerView的位置将通过接收新数据而改变

时间:2018-07-22 09:04:54

标签: android android-recyclerview recycler-adapter

我在notifyDataSetChanged中使用了recycleriew。像这样:

 private void setList(List<Article> articles) {

    mainList.addAll(articles);
    notifyDataSetChanged();
  }

但是我想在diffUtill中使用recycleriew。我这样创建了自己的diffUtill

public class ArticleListDiffTool extends DiffUtil.Callback {

  List<Article> oldList;
  List<Article> newList;

  private static final String TAG = "ArticleListDiffTool";
  public ArticleListDiffTool(List<Article> oldList, List<Article> newList) {

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

    Log.d(TAG, "ArticleListDiffTool: " + this.oldList.size() + "\n" + this.newList.size());
  }

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

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

  @Override
  public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
    return oldList.get(oldItemPosition).getId() .equals( newList.get(newItemPosition).getId());
  }

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

  @Nullable
  @Override
  public Object getChangePayload(int oldItemPosition, int newItemPosition) {
    //you can return particular field for changed item.
    return super.getChangePayload(oldItemPosition, newItemPosition);
  }
}

然后在适配器中使用它:

private void setList(列表文章){

    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new ArticleListDiffTool(this.mainList, articles),true);
    mainList.addAll(articles);
    diffResult.dispatchUpdatesTo(this);
  }

我想将新数据添加到我的旧列表中。但是,当收到新数据时,recyclerView将滚动到列表顶部。 但是我希望recyclerView处于用户状态,并将新数据添加到旧列表的其余部分。

3 个答案:

答案 0 :(得分:1)

如果您在recyclerview的末尾添加新项目,则在添加数据之前,将第一个可见项目存储在recyclerview中:

int position = ((LinearLayoutManager) recyclerView.GetLayoutManager()).findFirstVisibleItemPosition();

,然后进行所有更改并调用notifyDatasetChanged(),滚动到position

recyclerView.scrollToPosition(position);

答案 1 :(得分:1)

RecylcerView更新对您的视图一无所知。当您调用notifyDataSetChanged时,它将尝试确定哪些视图已移动或已替换。我看不到您使用setHasStableIds,因此在调用notifyDataSetChanged时它将假定所有内容均已替换。它将跳到位置0并完成操作。使用setHasStableIds时,它将检查可见项目的ID并更新其中的内容。它将停止跳来跳去。

现在,您还表明您正在使用DiffUtil。这很棒!当您不使用setHasStableIds时,这是正确告知recyclerView有关更改的方法。

您面临的问题是同时使用两者。要么移动到long id,然后让recyclerview自己进行比较,要么使用DiffUtil并删除对notifyDataSetChanged的调用。两种变体都应该起作用。

答案 2 :(得分:0)

几个小时后我发现了问题。

我每次想要更新recyclerView时都将接收到的数据发送到我的适配器 然后DiffUtil会将我的旧列表与收到的新零件进行比较,因此(完全是新商品),DiffUtil决定刷新整个recyclerView列表。

解决方案: 现在,我从recyclerView适配器获取当前列表,并使用addAll插入从服务器接收到的新项目,然后将此完整列表传递给适配器。

现在DiffUtil可以比较新旧列表之间的区别,并且recyclerView将保持在当前位置。