RecyclerView:如何清除 cached/recycled 视图?
RecyclerView: how to clear cached/recycled views?
我使用 RecyclerView 显示具有列表布局的项目列表。我从列表布局切换到网格布局,在网格布局中仅显示所有数据的一个子集。此开关使用与呈现列表布局时不同的布局 XML。
所有这一切都很好,除了当我滚动时,回收(缓存?)列表布局视图填充网格,与适当的网格布局视图项目混合。换句话说,我没有为 RecyclerView 中的每个项目布局使用我的 layout_grid.xml
,而是使用 layout_list.xml
布局获取项目,但采用网格格式。
这告诉我 LayoutManager 工作正常,从列表布局切换到网格布局。但并非所有项目视图项目都使用网格 xml 布局重新创建,而是使用循环列表布局视图。
我尝试了RecyclerView.removeAllViews()
、RecyclerView.removeAllViewInLayout()
、RecyclerView.swapAdapter()
(强制重新加载适配器),但都无济于事。
更新:
如果我在列表中向下滚动两个位置,然后从列表切换到网格,前两个位置不通过 onCreateViewHolder(),而是直接到 onBindViewHolder(),因此不会强制使用网格布局 xml。相反,前两个位置项目被回收(我认为)并以其列表布局格式显示。
好的,我明白了。你使用这两种布局?有一种方法可以 return list/grid 元素 (id/position) 的视图类型。您也正确地实现了此方法,适配器可以为新视图回收正确的布局。
你明白我的意思吗? :)
这里的关键是覆盖 getItemViewType(int position)
并进行设置,这样我就可以检查我正在为该位置处理的视图类型(列表或网格),然后为该位置设置适当的视图处理在 onbindViewHolder()
中的位置。下面,viewFormat
只是一个整数,当用户点击菜单按钮更改格式时,我将其设置为列表或网格。
@Override
public int getItemViewType(int position) {
if (listData.size() == 0) {
return EMPTY_VIEW;
} else if (viewFormat == Constants.LIST_FORMATTED) {
return Constants.LIST_FORMATTED;
} else if (viewFormat == Constants.GRID_CONDITION) {
return Constants.GRID_CONDITION;
}
return super.getItemViewType(position);
}
一位 post 对我的原创 post 发表评论的用户让我意识到了这一点,但不幸的是,这些评论已被删除。我感谢那个用户给我指明了正确的方向。
我遇到了同样的问题。 Mann 建议的解决方案效果很好。另一种选择是将 RecyclerView 的 RecycledViewPool 设置为新实例。这对我也适用。
recyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());
但我认为覆盖 getItemViewType() 是更简洁的解决方案。
听起来接受的答案适合您的情况,返回不同的 viewType 可能是您需要做的。
如果有人确实需要找到一种方法来清除缓存的视图持有者并最终出现在这个线程中,那么我发现这是有效的方法。
您需要调用 setLayoutManager(null)
和 setAdapter(null)
。如果你想保留你的适配器,你可以做类似 adapter = getAdapter(); setAdapter(null); setAdapter(adapter);
使用
recyclerView.getRecycledViewPool().clear();
Recyclerview 有视图缓存和回收视图池(view holders pool)。
缓存是视图(具有填充数据的视图)。当 LayoutManager 告诉 recyclerview 视图不再可见且不再需要时,recyclerview 检查该视图对于特定位置是否仍然有效,如果有效则将其添加到缓存中,因此下次 LM 请求该位置的视图时 returns 原样来自缓存。
那么什么是回收视图池?当视图从缓存中删除或不再是有效视图时,与这些视图相关的数据将被清除,只有视图持有者对象保留在池中。根据 itemType,池可以有不同项目类型的视图持有者。
现在,就您而言,您的观点对于该特定职位无效,因为您想要显示完全不同的观点。所以,你的适配器应该告诉 recyclerview 所有的视图都是无效的。唯一的方法是对所有项目使用 notifyDataSetChanged。 Recyclerview 将从缓存中删除视图并将其添加到回收器视图池中。所以现在LM请求view的时候,要么返回回收的view(根据itemType),要么返回新创建的view,adapter会为这些view绑定数据。
就这样做
简单!!
adapter.notifyItemRangeRemoved(0,adapter.getItemCount());
adapter.notifyItemRangeRemoved(0,adapter.getItemCount());
for (int i = 0; i < array.length(); i++) {
JSONObject object = array.getJSONObject(i);
////
data_List.add(data);
}
final int targetCacheSize = 2;
recyclerView.setItemViewCacheSize(Integer.MIN_VALUE);
recyclerView.getRecycledViewPool().clear();
recyclerView.setItemViewCacheSize(targetCacheSize);
我使用 RecyclerView 显示具有列表布局的项目列表。我从列表布局切换到网格布局,在网格布局中仅显示所有数据的一个子集。此开关使用与呈现列表布局时不同的布局 XML。
所有这一切都很好,除了当我滚动时,回收(缓存?)列表布局视图填充网格,与适当的网格布局视图项目混合。换句话说,我没有为 RecyclerView 中的每个项目布局使用我的 layout_grid.xml
,而是使用 layout_list.xml
布局获取项目,但采用网格格式。
这告诉我 LayoutManager 工作正常,从列表布局切换到网格布局。但并非所有项目视图项目都使用网格 xml 布局重新创建,而是使用循环列表布局视图。
我尝试了RecyclerView.removeAllViews()
、RecyclerView.removeAllViewInLayout()
、RecyclerView.swapAdapter()
(强制重新加载适配器),但都无济于事。
更新:
如果我在列表中向下滚动两个位置,然后从列表切换到网格,前两个位置不通过 onCreateViewHolder(),而是直接到 onBindViewHolder(),因此不会强制使用网格布局 xml。相反,前两个位置项目被回收(我认为)并以其列表布局格式显示。
好的,我明白了。你使用这两种布局?有一种方法可以 return list/grid 元素 (id/position) 的视图类型。您也正确地实现了此方法,适配器可以为新视图回收正确的布局。 你明白我的意思吗? :)
这里的关键是覆盖 getItemViewType(int position)
并进行设置,这样我就可以检查我正在为该位置处理的视图类型(列表或网格),然后为该位置设置适当的视图处理在 onbindViewHolder()
中的位置。下面,viewFormat
只是一个整数,当用户点击菜单按钮更改格式时,我将其设置为列表或网格。
@Override
public int getItemViewType(int position) {
if (listData.size() == 0) {
return EMPTY_VIEW;
} else if (viewFormat == Constants.LIST_FORMATTED) {
return Constants.LIST_FORMATTED;
} else if (viewFormat == Constants.GRID_CONDITION) {
return Constants.GRID_CONDITION;
}
return super.getItemViewType(position);
}
一位 post 对我的原创 post 发表评论的用户让我意识到了这一点,但不幸的是,这些评论已被删除。我感谢那个用户给我指明了正确的方向。
我遇到了同样的问题。 Mann 建议的解决方案效果很好。另一种选择是将 RecyclerView 的 RecycledViewPool 设置为新实例。这对我也适用。
recyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());
但我认为覆盖 getItemViewType() 是更简洁的解决方案。
听起来接受的答案适合您的情况,返回不同的 viewType 可能是您需要做的。
如果有人确实需要找到一种方法来清除缓存的视图持有者并最终出现在这个线程中,那么我发现这是有效的方法。
您需要调用 setLayoutManager(null)
和 setAdapter(null)
。如果你想保留你的适配器,你可以做类似 adapter = getAdapter(); setAdapter(null); setAdapter(adapter);
使用
recyclerView.getRecycledViewPool().clear();
Recyclerview 有视图缓存和回收视图池(view holders pool)。
缓存是视图(具有填充数据的视图)。当 LayoutManager 告诉 recyclerview 视图不再可见且不再需要时,recyclerview 检查该视图对于特定位置是否仍然有效,如果有效则将其添加到缓存中,因此下次 LM 请求该位置的视图时 returns 原样来自缓存。
那么什么是回收视图池?当视图从缓存中删除或不再是有效视图时,与这些视图相关的数据将被清除,只有视图持有者对象保留在池中。根据 itemType,池可以有不同项目类型的视图持有者。
现在,就您而言,您的观点对于该特定职位无效,因为您想要显示完全不同的观点。所以,你的适配器应该告诉 recyclerview 所有的视图都是无效的。唯一的方法是对所有项目使用 notifyDataSetChanged。 Recyclerview 将从缓存中删除视图并将其添加到回收器视图池中。所以现在LM请求view的时候,要么返回回收的view(根据itemType),要么返回新创建的view,adapter会为这些view绑定数据。
就这样做 简单!!
adapter.notifyItemRangeRemoved(0,adapter.getItemCount());
adapter.notifyItemRangeRemoved(0,adapter.getItemCount());
for (int i = 0; i < array.length(); i++) {
JSONObject object = array.getJSONObject(i);
////
data_List.add(data);
}
final int targetCacheSize = 2;
recyclerView.setItemViewCacheSize(Integer.MIN_VALUE);
recyclerView.getRecycledViewPool().clear();
recyclerView.setItemViewCacheSize(targetCacheSize);