【问题标题】:Recyclerview on Scrolling values changing from adapterRecyclerview 关于从适配器更改的滚动值
【发布时间】:2016-02-04 12:03:55
【问题描述】:

我正在开发一个应用程序,我正在尝试使用 RecyclerView 和回收器适配器填充列表。但是当我快速滚动列表时,有时列表项上的值会在列表项之间随机排列。对此有已知的解决方法吗?

【问题讨论】:

  • 项目不能自行更改,很可能您正在适配器中更改它们
  • 我的意思是内容在列表项之间洗牌
  • 谨慎使用viewholder模式或者如果你的列表很小设置setIsRecyclable(false);试试这个。
  • 在哪里放置 setIsRecyclable(false) ?@KundanKumarRoy
  • 在你的 onBindViewHolder 添加这个 holder.setIsRecyclable(false);

标签: android android-recyclerview


【解决方案1】:

在适配器中添加这个解决了问题

@Override
public int getItemViewType(int position)
{
    return position;
}

【讨论】:

  • 这行得通...但是有人可以解释一下这是如何工作的吗??
  • @Override public int getItemViewType(int position) { if (position
  • 谁能解释一下这是如何工作的?它对我有用,但我想知道背后发生了什么,谢谢!
  • 答案或许能解决您的问题。但它会导致回收中断。每行都有一个唯一的类型。
  • @zakjma 为什么你认为它坏了?
【解决方案2】:

只需在您的适配器类中覆盖这些方法:

@Override
public long getItemId(int position) {
    return position;
}

@Override
public int getItemViewType(int position) {
    return position;
}

此链接将帮助您了解背后的概念。

How to fix Recyclerview shuffling issue

【讨论】:

  • 返回 getItemViewType 作为位置基本上是要求再次绘制每个视图并且没有任何东西被回收。您不妨在创建 viewholder.setIsRecylable(false) 时设置 viewholder.setIsRecylable(false)。但这会破坏拥有recyclerview的目的。这个答案只是掩盖了真正的问题
  • 它也只是停止了我的点击事件,我不知道为什么..
【解决方案3】:

只需覆盖适配器中的两个方法,它就会解决您的问题。

@Override
public long getItemId(int position) {
    return position;
}

@Override
public int getItemViewType(int position) {
    return position;
}

【讨论】:

    【解决方案4】:

    注意:我强烈建议不要使用任何建议对所有列表项使用唯一视图类型的解决方案,方法是通过覆盖 getItemViewType() 将位置编号分配给视图类型。这样做会使 RecyclerView 认为列表中的所有项目都具有不同类型的布局,因此每个项目都将从头开始单独创建。这将导致增加应用程序的主内存使用量以及包含 RecyclerView 的 Activity 或 Fragment 的加载时间。

    带解释的简单最优解

    由于项目的 ViewHolder 未在 onBindViewHolder() 内正确更新,项目正在被洗牌。要知道为什么会出现这种行为,首先让我们了解 RecyclerView 究竟是如何回收列表项的。

    默认情况下,RecyclerView 只会创建可以在设备屏幕上显示的项目数。这意味着,即使列表中有数百或数千个列表项,如果设备一次只能在其屏幕上显示 10 个项目,那么大约只有 10 个项目将被创建并存储在主存储器 (RAM) 中。当屏幕滚动时,这 10 个项目将更新为新内容,而不是再次创建项目及其布局。在下图中,您可以看到仅通过将文本从 ABC 更新为 XYZ 来回收第一个项目。

    图片来源:谷歌代码实验室

    更具体地说,在滚动时,RecyclerView 将使用相同的已滚动项的 ViewHolder 并使用即将到来的新列表项的属性更新它,而不是垃圾收集已滚动项的 ViewHolder 并创建一个新的。 (ViewHolder 是保存特定列表项的视图和描述它的属性的东西)

    这个更新处理是通过覆盖onBindViewHolder() 方法来完成的,每当需要在屏幕上显示新项目时都会调用该方法。列表中的值随机播放的原因与 ViewHolder 在此方法中的更新方式有关。正如我之前所说,由于列表项在滚动列表时被回收,您作为onBindViewHolder() 的参数获得的 ViewHolder 将已经分配了一些其他列表项的属性。因此,您需要确保根据新列表项的属性替换此 ViewHolder 的所有属性或重置为默认值。为此,请检查您是否在此方法中使用了任何条件,并确保向其添加默认条件,该条件会将特定视图的属性重置为默认条件。

    示例:-

    if (<CONDITION>) {
       holder.textView.setText("New Text")
    } else {
       // RESET. Missing to reset the text would lead to the issue.
       holder.textView.setText("Default Text")
    }
    

    如果您仍然对 RecyclerView 的工作没有清楚的了解,那么我建议您通过 Google 浏览 RecyclerView Fundamentals codelab。在这个 Codelab 中,他们在第一个任务的第 6 步中专门解决了这个回收问题。

    【讨论】:

    • 这应该是公认的答案,因为所有其他的只是降低应用性能的一种方式。
    【解决方案5】:

    覆盖 getItemIdgetItemViewType 为我解决了这个问题。

    【讨论】:

      猜你喜欢
      • 2016-05-08
      • 2019-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-14
      相关资源
      最近更新 更多