滚动时防止 RecyclerView 显示以前的内容

Prevent RecyclerView showing previous content when scrolling

我有一个带有 GridLinearLayout 和自定义适配器的 RecyclerView。每一项的内容是使用json下载并解析的图片

基本上就是图片的网格

几乎一切正常,但是,当向下滚动内容并再次向上滚动时,它会在不到一秒的时间内显示每个项目中的先前视图,然后再次显示正确的图片。

我可以做些什么来防止或解决这个问题?提前感谢您提供的任何帮助 and/or 指导。

这是适配器代码:

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

顾名思义RecyclerView 回收视图以优化内存,以便显示上一个视图的内容。由于您是从 Internet 加载图像,因此加载图像所需的时间很短,因此可以观察到先前图像的内容。您可以执行以下操作之一。

1) 在加载实际图像之前从本地资源设置默认图像,最好是小尺寸图像以保留 memory.something 像这样

//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) 在加载图像之前将 ImageView 可见性设置为 GONE/INVISIBLE,并在图像加载后再次使其可见。

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

我认为你应该像这样添加占位符:

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

或者先设置默认图片

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

覆盖 onViewRecycled (VH holder) 以将图像设置为空。

像这样:

public void onViewRecycled (VH holder) {

   holder.wall.setImageBitmap(null);
}