java android adapter android-recyclerview palette

java - Evitar que RecyclerView muestre contenido anterior cuando se desplaza



android adapter (3)

Tengo un RecyclerView con un GridLinearLayout y un adaptador personalizado. El contenido de cada elemento es una imagen descargada usando un json y analizándolo.

Básicamente es una grilla de imágenes.

Todo funciona casi bien, pero, sin embargo, al desplazarse hacia abajo por el contenido y volver a subir, muestra las vistas anteriores en cada elemento durante menos de un segundo y luego vuelve a mostrar la imagen adecuada.

¿Qué podría hacer para prevenir o solucionar esto? Gracias de antemano por cualquier ayuda y / o guía que pueda proporcionar.

Este es el código del adaptador:

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


Como su nombre indica, RecyclerView recicla las vistas para optimizar la memoria, por lo que muestra el contenido de la vista anterior. Como está cargando la imagen desde Internet, tarda poco tiempo en cargar la imagen para poder observar el contenido de la imagen anterior. Puedes hacer una de las siguientes cosas.

1) Establezca una imagen predeterminada del recurso local antes de cargar la imagen real, preferiblemente una imagen de tamaño pequeño para conservar la memoria. Algo como esto

//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) Establezca la visibilidad de ImageView en GONE / INVISIBLE antes de cargar la imagen y hacerla VISIBLE nuevamente después de cargar la imagen.

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


Creo que deberías agregar un marcador de posición así:

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

o establecer la imagen predeterminada al principio.

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


Sobrescribe onViewRecycled (VH holder) para establecer la imagen como nula.

Me gusta esto:

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