使用 RecyclerView 适配器更新数据的最佳方法 [重复]

Posted

技术标签:

【中文标题】使用 RecyclerView 适配器更新数据的最佳方法 [重复]【英文标题】:Best way to update data with a RecyclerView adapter [duplicate] 【发布时间】:2015-07-15 05:23:39 【问题描述】:

当我必须使用带有 ListView 的经典适配器时,我会像这样更新 ListView 中的数据:

myAdapter.swapArray(data);

public swapArray(List<Data> data) 
  clear();
  addAll(data);
  notifyDataSetChanged();

我想知道RecyclerView 的最佳做法是什么。因为在 RecyclerView 适配器中,您不能像在 ListView 中那样执行 clearaddAll

所以我只尝试了notifyDataSetChanged,但没有成功。 然后我尝试在我的视图中使用 swapAdapter:

List<Data> data = newData;

MyRecyclerAdapter adapter = new MyRecyclerAdapter(data);

// swapAdapter on my recyclerView (instead of a .setAdapter like with a classic listView).
recyclerViewList.swapAdapter(adapter, false);

但是使用最后一个解决方案,我仍然需要创建一个新的适配器实例,我觉得这不是最好的解决方案。我应该能够在没有新的MyRecyclerAdapter 的情况下更改我的数据。

【问题讨论】:

最好(对于动画和性能)发送详细的通知事件(例如 notfiyItemInserted/Removed/Moved/Changed)。另请查看 SortedList 类,如果您的列表中有排序标准,它可以为您计算这些值。 我正在处理我的适配器 notifyDataSetChanged() 中的每一项更改; notifyDataSetChanged() 是性能最差的方法。把它当作最后的机会。正如@yigit 所建议的,请参阅***.com/questions/31367599/… 获取notifyItemRangeInserted/Removed/Moved/Changed 【参考方案1】:

RecyclerView 的适配器没有很多方法,而 ListView 的适配器中没有其他可用的方法。但是你的交换可以很简单地实现为:

class MyRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> 
   List<Data> data;
   ...

    public void swap(ArrayList<Data> datas)
    
        data.clear();
        data.addAll(datas);
        notifyDataSetChanged();     
    

也有区别

list.clear();
list.add(data);

list = newList;

首先是重用同一个列表对象。另一个是取消引用和引用列表。无法再访问的旧列表对象将被垃圾收集,但必须先堆积堆内存。这与每次要交换数据时初始化新适配器相同。

【讨论】:

虽然上面的方法适用于简单的 list.size(),但我的数据有点复杂,因为我在 recyclerview 中有多个列表。回收站视图列表视图由多个视图类型管理。因此,很难删除不可见或未由 bindViewholder 绑定的列表项子集。对我有用的唯一方法是 RecyclerView.swapAdapter(); 上面提到的 swap(ArrayList datas) 不起作用,Log.d 注释方法 RecyclerView.swapAdapter(); ,无论如何,我首先找到了我自己清除数据源(创建位置的ArrayList)的方法,接下来使用适配器中的方法清除适配器数据源,然后再次使用新数据创建新数据源(ArrayList),然后将该数据添加到适配器arraylist,最后notifydatasetchanged() 方法。 @inmyth 可能在您上面的答案中进行编辑:应该“notifyDataSetChanged();”是“data.notifyDataSetChanged();” ? 我不明白你为什么不允许加载一个空的数据集。如果我想清除我的 RecyclerView 怎么办? datas.size==0 不应该真的存在。 我的答案已被许多不同的人多次编辑。你是对的,唯一需要的检查就是 null。【参考方案2】:

@inmyth 的回答是正确的,只是稍微修改一下代码,处理空列表。

public class NewsAdapter extends RecyclerView.Adapter<...>     
    ...
    private static List mFeedsList;
    ...    
    public void swap(List list)
            if (mFeedsList != null) 
                mFeedsList.clear();
                mFeedsList.addAll(list);
            
            else 
                mFeedsList = list;
            
            notifyDataSetChanged();
    

我正在使用 Retrofit 来获取列表,在 Retrofit 的 onResponse() 使用中,

adapter.swap(feedList);

【讨论】:

您好,我正在努力在我的项目中使用此代码,其中使用改造从 api 获取数据,您介意帮助我吗? clear 和 addAll 对我来说是红色的 Kotlin 翻译。【参考方案3】:

DiffUtil 是更新 RecyclerView Adapter 中数据的最佳选择,您可以在 android 框架中找到。 DiffUtil 是一个实用类,可以计算两个列表之间的差异,并输出一个更新操作列表,将第一个列表转换为第二个列表。

大多数时候我们的列表完全改变,我们将新列表设置为 RecyclerView Adapter。我们调用 notifyDataSetChanged 来更新适配器。 NotifyDataSetChanged 代价高昂。 DiffUtil 类现在解决了这个问题。它完美地完成了它的工作!

【讨论】:

【参考方案4】:

发现以下解决方案适用于我的类似问题:

private ExtendedHashMap mData = new ExtendedHashMap();
private  String[] mKeys;

public void setNewData(ExtendedHashMap data) 
    mData.putAll(data);
    mKeys = data.keySet().toArray(new String[data.size()]);
    notifyDataSetChanged();

使用清除命令

mData.clear()

不是必需品

【讨论】:

以上是关于使用 RecyclerView 适配器更新数据的最佳方法 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Android RecyclerView MVVM 在哪里使用 notifyDataSetChanged 更新 Adapter

RecyclerView 适配器 - 列表正在更新,但视图没有

如何使用 DiffUtil 更新 RecyclerView 适配器

如何从另一个项目更新recyclerview项目中的数据?

从RecyclerView适配器更新活动或片段的视图

用户交互后如何根据 RecyclerView 适配器内部服务器的响应更新 TextView?