Issue Summary
I have a RecyclerView list in an activity with an actionBar button used to switch the RecyclerView between a LIST and a GRID layout.
The layouts of the items are different when viewing the list as a LIST and as a GRID.
When viewing the items in a LIST the row format is
|----|
|icon| Item Name
|----|
When viewing the items in a GRID the row format is
|--------------|
| large icon |
| |
| |
| |
|--------------|
Item Name
Therefore viewing my list as i LIST i see
|----|
|icon| Item1
|----|
|----|
|icon| Item2
|----|
|----|
|icon| Item3
|----|
|----|
|icon| Item3
|----|
and when viewing my list as a GRID i see
|--------------| |--------------|
| large icon | | large icon |
| | | |
| | | |
| | | |
|--------------| |--------------|
Item1 Item2
|--------------| |--------------|
| large icon | | large icon |
| | | |
| | | |
| | | |
|--------------| |--------------|
Item3 Item4
When i use the actionBar button to toggle the list view from LIST to GRID or GRID to LIST, some views are still rendered in the layout for the other style. I believe its the views which you scrolled out of sight before switching are recycled and reused rather than recreated.
For example if i go from GRID to LIST i see
|--------------|
| large icon |
|----| | |
|icon| Item1 | |
|----| | |
|--------------|
Item2
|--------------| |--------------|
| large icon | | large icon |
| | | |
| | | |
| | | |
|--------------| |--------------|
Item3 Item4
Background code information
I have 2 layout managers; one for each layout style
private RecyclerView.LayoutManager linearLayoutManager;
private RecyclerView.LayoutManager gridLayoutManager;
In the adapter i store whether i am displaying the list as a grid or list
enum ListViewEnum{
LIST,
GRID
}
ListViewEnum listViewStyle = ListViewEnum.LIST;
public ListViewEnum getListStyle() {
return listViewStyle;
}
The layout of the items in the list depend on whether the list is being rendered as a list or a grid.
ViewHolderList
ViewHolderGrid
When creating the view holder, I base the type of View Holder on the adapters list view style
protected RecyclerView.ViewHolder getItemViewHolder(ViewGroup parent){
if (listViewStyle == ListViewEnum.LIST){
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_row, parent, false);
return new ViewHolderList(itemView, ....);
} else {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_row, parent, false);
return new ViewHolderGrid(itemView, ....);
}
}
When the user clicks the actionBar button i toggle the adapter's value
getListAdapter().setListViewMode(ListViewMode.LIST);
I then refresh
listView.setLayoutManager(getListAdapter().getListStyle() == ListViewEnum.LIST ? linearLayoutManager : gridLayoutManager);
getListAdapter().notifyDataSetChanged();
listView.invalidateItemDecorations();
invalidateOptionsMenu();
I understand that i am refreshing the list adapter but it is not letting go of recycledViews. Debugging shows that on clicking the toggle button i see calls to just "onBindViewHolder" for some positions (the recycled ones) and "onCreateViewHolder" and "onBindViewHolder"(for the new ones) therefore indicating that the old view holders are being recycled.
How do i refresh the list so that it does not re-use ViewHolders from the wrong list style?