Android RecyclerView:如何清除缓存/回收的视图?

Android RecyclerView:如何清除缓存/回收的视图?,android,android-recyclerview,Android,Android Recyclerview,我使用RecyclerView以列表布局显示项目列表。我从列表布局切换到网格布局,在网格布局中只显示所有数据的子集。此开关使用与显示列表布局时不同的布局XML 所有这些都很好,除了当我滚动时,回收(缓存?)列表布局视图填充网格,并与适当的网格布局视图项混合。换句话说,我不是在RecyclerView中为每个项目的布局使用我的layout\u grid.xml,而是使用layout\u list.xmllayout来获取项目,而是使用网格格式 这告诉我LayoutManager工作正常,从列表切换

我使用RecyclerView以列表布局显示项目列表。我从列表布局切换到网格布局,在网格布局中只显示所有数据的子集。此开关使用与显示列表布局时不同的布局XML

所有这些都很好,除了当我滚动时,回收(缓存?)列表布局视图填充网格,并与适当的网格布局视图项混合。换句话说,我不是在RecyclerView中为每个项目的布局使用我的
layout\u grid.xml
,而是使用
layout\u list.xml
layout来获取项目,而是使用网格格式

这告诉我LayoutManager工作正常,从列表切换到网格布局。但并非所有项目视图项目都使用网格xml布局重新创建,而是使用循环列表布局视图

我尝试了
RecyclerView.removeAllViews()
RecyclerView.removeAllViewInLayout()
RecyclerView.swapAdapter()
(强制重新加载适配器),但都没有用

更新:


如果我向下滚动列表中的两个位置,然后从列表切换到网格,前两个位置不会经过onCreateViewHolder(),而是直接到onBindViewHolder(),因此不会强制使用网格布局xml。相反,前两个位置项被回收(我认为)并以列表布局格式显示。

现在我明白了。两种布局都使用吗?有一种方法可以返回列表/网格元素(id/位置)的viewtype。您还必须正确地实现此方法,以便适配器可以为新视图回收正确的布局。
你明白我的意思吗?:)

这里的关键是覆盖
getItemViewType(int position)
并对其进行设置,以便我可以检查针对该位置处理的视图类型(列表或网格),然后在
onbindViewHolder()
中为该位置设置适当的视图处理。下面,
viewFormat
只是一个int,当用户点击菜单按钮更改格式时,我将其设置为list或grid

@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);
    }

一位在我的原始帖子上发表评论的用户让我意识到了这一点,但不幸的是,这些评论被删掉了。我感谢该用户为我指明了正确的方向

我也有同样的问题。曼恩提出的解决方案效果很好。另一个选项是将RecycleView的RecycledViewPool设置为新实例。这对我也适用

recyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());

但是我认为覆盖getItemViewType()是一个更干净的解决方案。

听起来,对于您的情况,接受的答案是正确的,返回不同的viewType可能是您需要做的

如果有人真的需要找到一种方法来清除缓存的视图持有者,并最终进入这个线程,下面是我发现有效的方法

您需要调用
setLayoutManager(null)
setAdapter(null)
。如果要保留适配器,可以执行类似于
adapter=getAdapter()的操作;setAdapter(空);设置适配器(适配器)

使用

recyclerView.getRecycledViewPool().clear();

Recyclerview具有视图缓存和回收视图池(视图池)

缓存是一组视图(包含填充数据的视图)。当LayoutManager告诉recyclerview视图不再可见且不再需要时,recyclerview会检查该视图对于特定位置是否仍然有效,如果该视图有效,则会将其添加到缓存中,因此当LM下次请求该位置的视图时,它会按原样从缓存中返回

那么什么是可回收的意见池?当视图从缓存中删除或不再是有效视图时,将清除与这些视图相关的数据,并且池中只保留视图持有者对象。根据项目类型,池可以有不同项目类型的视图持有者

现在,在您的情况下,您的视图对于该特定位置无效,因为您希望显示完全不同的视图。因此,适配器应该告诉recyclerview所有视图都无效。唯一的方法是对所有项目使用notifyDataSetChanged。Recyclerview将从缓存中删除视图,并将这些视图添加到recyler视图池。所以现在,当LM请求查看时,将返回回收的视图(根据itemType)或新创建的视图,适配器将数据绑定到这些视图。

只需执行此操作 简单

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);
                    }
adapter.notifyItemRangeRemoved(0,adapter.getItemCount());
已删除adapter.notifyItemRange(0,adapter.getItemCount());
对于(int i=0;i
我实现了一个getItemViewType(int位置)来确定我是否有一个空视图。我是否应该在那里四处走动以确定我正在处理的视图类型?是的,完全正确。否则,recyclerview没有机会知道要循环使用哪种视图类型。OK,我明白你的意思了。但是在哪里设置视图类型?对于列表或网格布局,它似乎返回0。您必须根据索引手动返回viewtype,然后可以在create方法/bindViewHolder方法AHH中读取它。。。我懂了。体力劳动。:-)我今晚要试试这个(现在要跑了)。谢谢你给我指出这一点。如果成功,我将在完成后标记答案。在我的情况下,设置
layoutmanager(null)
setAdapter(null)
对我来说很有效。这使我免于拔头发!欢迎来到堆栈溢出。你能为你的代码和它如何回答这个问题添加一些解释吗?
final int targetCacheSize = 2;
    recyclerView.setItemViewCacheSize(Integer.MIN_VALUE);
    recyclerView.getRecycledViewPool().clear();
    recyclerView.setItemViewCacheSize(targetCacheSize);