Prevent RecyclerView from showing previous content when scrolling

I have a RecyclerView with a GridLinearLayout and a custom adapter. The content of each element is an image uploaded using json and parsing it.

This is mainly an image grid.

Everything works almost fine, but when you scroll the content and repeat up, it displays the previous views in each element for less than a second, and then shows the correct image again.

What can I do to prevent or correct this? Thanks in advance for any help and / or advice you could provide.

This is the adapter code:

package jahirfiquitiva.project.adapters; import android.content.Context; import android.graphics.Bitmap; import android.support.v7.graphics.Palette; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import jahirfiquitiva.project.activities.WallpapersActivity; import com.koushikdutta.async.future.FutureCallback; import com.koushikdutta.ion.Ion; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; import jahirfiquitiva.project.R; public class WallpapersAdapter extends RecyclerView.Adapter<WallpapersAdapter.WallsHolder> { public interface ClickListener { void onClick(WallsHolder view, int index, boolean longClick); } private ArrayList<HashMap<String, String>> data; private final Context context; private boolean usePalette = true; private final ClickListener mCallback; private final Map<String, Palette> mPaletteCache = new WeakHashMap<>(); public WallpapersAdapter(Context context, ClickListener callback) { this.context = context; this.data = new ArrayList<>(); this.mCallback = callback; } public void setData(ArrayList<HashMap<String, String>> data) { this.data = data; notifyDataSetChanged(); } @Override public WallsHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(context); return new WallsHolder(inflater.inflate(R.layout.wallpaper_item, parent, false)); } @Override public void onBindViewHolder(final WallsHolder holder, int position) { Animation anim = AnimationUtils.loadAnimation(context, android.R.anim.fade_in); HashMap<String, String> jsondata = data.get(position); holder.name.setText(jsondata.get(WallpapersActivity.NAME)); final String wallurl = jsondata.get(WallpapersActivity.WALL); holder.wall.startAnimation(anim); holder.wall.setTag(wallurl); Ion.with(context) .load(wallurl) .asBitmap() .setCallback(new FutureCallback<Bitmap>() { @Override public void onCompleted(Exception e, Bitmap result) { holder.progressBar.setVisibility(View.GONE); if (e != null) { e.printStackTrace(); } else if (holder.wall.getTag() != null && holder.wall.getTag().equals(wallurl)) { holder.wall.setImageBitmap(result); if (usePalette) { Palette p; if (mPaletteCache.containsKey(wallurl)) { p = mPaletteCache.get(wallurl); } else { p = new Palette.Builder(result).generate(); mPaletteCache.put(wallurl, p); } if (p != null) { Palette.Swatch wallSwatch = p.getVibrantSwatch(); if (wallSwatch != null) { holder.titleBg.setBackgroundColor(wallSwatch.getRgb()); holder.titleBg.setAlpha(1); holder.name.setTextColor(wallSwatch.getTitleTextColor()); holder.name.setAlpha(1); } } } } } }); } @Override public int getItemCount() { return data.size(); } public class WallsHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { public final View view; public final ImageView wall; public final TextView name; public final ProgressBar progressBar; public final LinearLayout titleBg; WallsHolder(View v) { super(v); view = v; wall = (ImageView) v.findViewById(R.id.wall); name = (TextView) v.findViewById(R.id.name); progressBar = (ProgressBar) v.findViewById(R.id.progress); titleBg = (LinearLayout) v.findViewById(R.id.titlebg); view.setOnClickListener(this); view.setOnLongClickListener(this); } @Override public void onClick(View v) { int index = getLayoutPosition(); if (mCallback != null) mCallback.onClick(this, index, false); } @Override public boolean onLongClick(View v) { int index = getLayoutPosition(); if (mCallback != null) mCallback.onClick(this, index, true); return false; } } } 
+5
source share
3 answers

As the name implies, RecyclerView processes the view to optimize memory to display the contents of the previous view. Since you are downloading an image from the Internet, downloading an image takes little time, so you can observe the contents of the previous image. You can do one of the following:

1) Set the default image from the local resource before loading the actual image, preferably a small image to save memory. Something like that

 //load default image first holder.wall.setImageResource(R.id.your_default_image_resource); //load actual image Ion.with(context) .load(wallurl) .asBitmap() .setCallback(new FutureCallback<Bitmap>() { @Override public void onCompleted(Exception e, Bitmap result) { holder.progressBar.setVisibility(View.GONE); if (e != null) { e.printStackTrace(); } else if (holder.wall.getTag() != null && holder.wall.getTag().equals(wallurl)) { holder.wall.setImageBitmap(result); if (usePalette) { Palette p; if (mPaletteCache.containsKey(wallurl)) { p = mPaletteCache.get(wallurl); } else { p = new Palette.Builder(result).generate(); mPaletteCache.put(wallurl, p); } if (p != null) { Palette.Swatch wallSwatch = p.getVibrantSwatch(); if (wallSwatch != null) { holder.titleBg.setBackgroundColor(wallSwatch.getRgb()); holder.titleBg.setAlpha(1); holder.name.setTextColor(wallSwatch.getTitleTextColor()); holder.name.setAlpha(1); } } } } } }); 

2) Before loading the image, set ImageView GONE / INVISIBLE, then press VISIBLE again after loading the image.

  //hide the imageview holder.wall.setVisibility(View.INVISIBLE); Ion.with(context) .load(wallurl) .asBitmap() .setCallback(new FutureCallback<Bitmap>() { @Override public void onCompleted(Exception e, Bitmap result) { holder.progressBar.setVisibility(View.GONE); if (e != null) { e.printStackTrace(); } else if (holder.wall.getTag() != null && holder.wall.getTag().equals(wallurl)) { //show the imageview and set bitmap holder.wall.setVisibility(View.VISIBLE); holder.wall.setImageBitmap(result); if (usePalette) { Palette p; if (mPaletteCache.containsKey(wallurl)) { p = mPaletteCache.get(wallurl); } else { p = new Palette.Builder(result).generate(); mPaletteCache.put(wallurl, p); } if (p != null) { Palette.Swatch wallSwatch = p.getVibrantSwatch(); if (wallSwatch != null) { holder.titleBg.setBackgroundColor(wallSwatch.getRgb()); holder.titleBg.setAlpha(1); holder.name.setTextColor(wallSwatch.getTitleTextColor()); holder.name.setAlpha(1); } } } } } }); 
+3
source

Overwrite onViewRecycled (VH holder) to set the image to null.

Like this:

 public void onViewRecycled (VH holder) { holder.wall.setImageBitmap(null); } 
+2
source

I think you should add a place owner like this:

 Ion.with(context).load("http://example.com/image.png") .withBitmap() .placeholder(R.drawable.placeholder_image) .error(R.drawable.error_image) .intoImageView(imageView); 

or first set the default image.

 holder.wall.setImageResource(R.drawable.placeholder_image); 
0
source

All Articles