'RecyclerView items duplicate and constantly changing
What's Happening:
The list (RecyclerView)
is mixing up the data when I scroll.
I.E when I scroll back up after scrolling down, some of the list items are repeated, not displaying proper content.
package jamesnguyen.newzyv2.UI_update;
import android.content.Context;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import jamesnguyen.newzyv2.R;
import jamesnguyen.newzyv2.RSS_Processcors.RssItem;
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.FeedViewHolder> {
private static List<RssItem> items = null;
private static Context context;
public RVAdapter(Context context, List<RssItem> items) {
this.items = items;
this.context = context;
}
public static List<RssItem> getItems() {
return items;
}
@Override
public RVAdapter.FeedViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
return new FeedViewHolder(v);
}
@Override
public void onBindViewHolder(RVAdapter.FeedViewHolder holder, int position) {
FeedViewHolder.getTitle().setText(items.get(position).getTitle());
FeedViewHolder.getPubDate().setText(items.get(position).getPubDate());
//FeedViewHolder.getDescription().setText(items.get(position).getDescription());
}
@Override
public long getItemId(int id) {
return id;
}
@Override
public int getItemCount() {
return items.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public static class FeedViewHolder extends RecyclerView.ViewHolder {
private static CardView cv;
private static TextView title;
private static TextView pubDate;
private static TextView description;
FeedViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.cv);
title = (TextView) itemView.findViewById(R.id.title);
pubDate = (TextView) itemView.findViewById(R.id.pubDate);
//description = (TextView) itemView.findViewById(R.id.description);
}
public static TextView getTitle() {
return title;
}
public static TextView getPubDate() {
return pubDate;
}
public static TextView getDescription() {
return description;
}
}
}
I believe maybe some works have to be done with the recycling process of RecyclerView but nothing i tried seesm to work.
Solution 1:[1]
done .
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
Solution 2:[2]
Only two things in your RecyclerView adapter
@Override
public long getItemId(int position) {
return position;
}
and in constructor of adapter
setHasStableIds(true);
Hope it helps!
Solution 3:[3]
The problem is the CardView
and TextView
objects are declared static inside the FeedViewHolder
. That means that all the calls trying to set the title in the onBindViewHolder
method hit the latest inflated View.
The fix is to remove the static
from cv
, title
, pubDate
, description
, then implement some non static setters like:
public void setTitle(String s) {
title.setText(s);
}
To be called in the onBindViewHolder
method:
@Override
public void onBindViewHolder(RVAdapter.FeedViewHolder holder, int position) {
holder.setTitle(items.get(position).getTitle());
//...
}
Solution 4:[4]
I had the same problem with a big grid recyclerview with hundreds of numbers that should have appeared sequentially but their order was getting mixed up and repeated.
// More concise code with Kotlin expressions
override fun getItemId(position: Int) = position.toLong()
override fun getItemViewType(position: Int) = position
Added above lines to the adapter.
Solution 5:[5]
In kotlin with clearing the previous items from the LinearLayout list item from the RecyclerView
override fun onBindViewHolder(view: MyViewHolder, index: Int) {
view.guideLinearLayout.removeAllViews()
/* do binding here*/
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
Solution 6:[6]
Just add
override fun getItemViewType(position: Int): Int {
return position
}
Solution 7:[7]
use holder.setIsRecyclable(false); in onBindViewHolder of your adapter class
Solution 8:[8]
If anybody using kotlin, use like inside RecyclerView.Adapter
The setHasStableId(true) is to be applied to the adapter of RecylerView
init {
setHasStableIds(true);
}
Override the position with product id
override fun getItemId(position: Int): Long {
return myList?.get(position).id
}
Solution 9:[9]
This question may be old but some information is not revealed. I faced a similar issue and stumbled on this question. After doing research for many weeks, I realized that overriding
@Override
public long getItemId(int position) {
return position;
}
and
@Override
public int getItemViewType(int position) {
return position;
}
did not help me(It may help another person tho).
The issue was that the views were recycled. But that is not an issue because that is the main essence of recyclerview. So, here is the fix
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
holder.title.setText(null)
}
When views are recycled, its viewholder still has the previous value of where it was used. If (items.get(position).getTitle()
returns a value, it resets the text value of title correctly, else if it returns null, it retains the value from the recycled view. So, the example I just showed you resets the text value of the title to null
whenever a view is recycled.
Solution 10:[10]
If you use RecyclerView and your adapter extends PagedListAdapter or ListAdapter, then use this way to prevent duplication of the items when you click on them.
int position = getAdapterPosition();
Movie movie = getCurrentList().get(position);
It is my case, but change the object according to your project. This solution works, take a look here
Solution 11:[11]
The answer by Sujit Yadav is good for JAVA
Here is the solution in Kotlin
class MyAdapter() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
init {
setHasStableIds(true)
}
override fun getItemCount(): Int {
return list.size
}
override fun getItemViewType(position: Int): Int {
return position
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
...
}
Solution 12:[12]
i had same problem and this solution worked for me fine
holder.setIsRecyclable(false);
Hope it helps
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow