RecyclerView: how to clear cached/recycled views?

女生的网名这么多〃 提交于 2019-11-30 21:34:26

问题


I use a RecyclerView to display a list of items with a list layout. I switch from a list layout to a grid layout, showing just a subset of all the data when in grid layout. This switch uses a different layout XML than when list layout is presented.

All this works well, except that when I scroll, recycled (cached?) list layout views populate the grid, mixed in with proper grid layout view items. In other words, instead of using my layout_grid.xml for each item's layout in the RecyclerView, I get items using the layout_list.xml layout, but in a grid format.

This tells me the LayoutManager is working correctly, switching from a list to grid layout. But not all item view items are recreated using the grid xml layout, but rather recycled list layout views are used.

I tried RecyclerView.removeAllViews(), RecyclerView.removeAllViewInLayout(), RecyclerView.swapAdapter() (to force adapter reload), all to no avail.

Update:

If I scroll two positions down in the list, and then switch from list to grid, the first two positions do not go through onCreateViewHolder(), but straight to onBindViewHolder() and are therefore not forced to use the grid layout xml. Instead those first two position items are recycled (I think) and displayed in their list layout format.


回答1:


Ok now I understand. You use both layouts? There is a method to return the viewtype for a list/grid element (id/position). You have too implement this method correctly that the adapter can recycle the correct layout for the new view. Do you understand what I mean? :)




回答2:


Use

recyclerView.getRecycledViewPool().clear();



回答3:


I had the same problem. The solution suggested by Mann works well. An other option would be to set the RecycledViewPool of the RecyclerView to a new instance. That works for me as well.

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

But I think overriding the getItemViewType() is the cleaner solution.




回答4:


It sounds like the accepted answer is the right one for your case, returning a different viewType is probably what you needed to do.

If anyone does need to find a way to clear cached view holders and ended up in this thread, here is what I found that worked.

You need to call setLayoutManager(null) and setAdapter(null). If you want to keep your adapter, you can do something like adapter = getAdapter(); setAdapter(null); setAdapter(adapter);




回答5:


They key here was to override getItemViewType(int position) and set it up so that I could check which view type (list or grid) I'm dealing with for that position and then set the appropriate view handling for that position in onbindViewHolder(). Below, viewFormat is simply an int that I set to either list or grid when the user taps the menu button to change the format.

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

A user who posted comments on my original post made me aware of this, but unfortunately those comments were edited out. I thank that user for pointing me in the right direction.




回答6:


Recyclerview has view caching as well as recycled views pool (view holders pool).

Cache is of views (views with populated data). When LayoutManager tells recyclerview that view is no longer visible and needed, recyclerview checks if that view is still valid for particular position, if it is valid then it is added to cache, so when next time LM asks for the view for that position it returns from cache as it is.

Then what is recycled views pool? When views are removed from cache or are no more valid views, then data related to those views is cleared and only view holder object is kept in pool. Depending on itemType, pool can have view holders of different item types.

Now, in your case, your views are not valid for that particular position as you want to show altogether different view. So, your adapter should tell recyclerview that all the views are invalid. Only way to do is by using notifyDataSetChanged for all items. Recyclerview will remove views from cache and add those to recyler views pool. So now, when LM asks for view, either recycled view(according to itemType) or newly created view will be returned, and adapter will bind data to these views.




回答7:


Just do this Simple !!

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



回答8:


final int targetCacheSize = 2;
    recyclerView.setItemViewCacheSize(Integer.MIN_VALUE);
    recyclerView.getRecycledViewPool().clear();
    recyclerView.setItemViewCacheSize(targetCacheSize);


来源:https://stackoverflow.com/questions/27951473/recyclerview-how-to-clear-cached-recycled-views

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!