我正在开发一个应用程序,我正在尝试使用RecyclerView和回收器适配器填充列表。但是当我快速滚动列表时,有时列表项中的值会在列表项之间进行洗牌。这有一个已知的解决方案吗?
答案 0 :(得分:35)
在适配器中添加这个解决了问题
@Override
public int getItemViewType(int position)
{
return position;
}
答案 1 :(得分:12)
在适配器类中重写这些方法:
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
此链接将帮助您了解背后的概念。
答案 2 :(得分:2)
只需要在适配器中覆盖两个方法,它就可以解决您的问题。
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
答案 3 :(得分:1)
覆盖getItemId
和getItemViewType
为我解决了问题。
答案 4 :(得分:0)
以下解决方案对我有用。
在适配器类的holder.setIsRecyclable(false);
方法中添加onCreateViewHolder()
@NonNull
@Override
public OrderReportsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.item_portfolio_rec, parent, false);
OrderReportsViewHolder holder = new OrderReportsViewHolder(view);
holder.setIsRecyclable(false); //Add this Line
return holder;
}
在适配器类中添加getItemId(int position)
和getItemViewType(int position)
覆盖方法
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
答案 5 :(得分:0)
由于您没有在onBindViewHolder()
内正确更新项目的ViewHolder,因此这些项目变得井井有条。要了解为什么会发生此行为,您需要知道RecyclerView如何准确地回收列表项。
默认情况下,RecyclerView将仅创建可以在设备屏幕上显示的项目数量。这意味着即使列表中有成百上千个列表项,如果设备一次只能在其屏幕上显示10个项,那么大约只有10个项将被创建并存储在主存储器(RAM)中。滚动屏幕时,将使用新内容更新这10个项目,而不是创建一个新内容。在下图中,您只需将文本从ABC更新为XYZ,就可以看到第一个项目得到回收。
图片来源:Google Codelabs
更具体地说,在滚动时,RecyclerView不会使用垃圾桶来收集滚动的项目的ViewHolder并创建一个新对象,而不是垃圾回收它,而是使用相同的滚动的项目的ViewHolder并使用即将到来的新列表项目的属性对其进行更新。 (ViewHolder是用于保存特定列表项的视图和描述它的属性的东西)
此更新处理是通过覆盖onBindViewHolder()
方法来完成的,只要需要在屏幕上显示新项目,该方法就会被调用。列表中的值混洗的原因与您在此方法中更新ViewHolder的方式有关。正如我之前说过的那样,由于列表项被回收,因此在滚动列表时,您作为onBindViewHolder()
的参数获取的ViewHolder将已经分配了其他列表项的属性。因此,您需要确保根据新列表项的属性替换此ViewHolder的所有属性,或者将其重置为默认属性。为此,请检查您是否在此方法内使用了任何条件,并确保向其添加了默认条件,该条件会将特定视图的属性重置为默认条件。
示例:-
if (<CONDITION>) {
holder.textView.setText("New Text")
} else {
// reset
holder.textView.setText("Default Text")
}
最后,我强烈建议您不要使用其他建议您对所有列表项使用唯一视图类型的解决方案,只需通过覆盖getItemViewType()
将位置编号分配给视图类型即可。这样做会使RecyclerView认为列表中的所有项目都具有不同的布局类型,因此每个项目都将从头创建。这将导致您的应用程序的主内存使用量增加,并导致包含RecyclerView的活动或片段的加载时间增加。
如果您仍然不清楚RecyclerView的工作原理,那么建议您阅读Google的RecyclerView Fundamentals codelab。在此代码实验室中,他们甚至在其第一个任务的第6步中专门解决了此回收问题。