RecyclerView 显示错误的图像

RecyclerView displaying wrong Images

以下是我用来显示包含电影图像和电影标题的电影项目的适配器代码。

   public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.MovieViewHolder> {

 private List<Movie> movieList;



public MovieAdapter(List<Movie> movieList){
   this.movieList = movieList;
}

@Override
public MovieViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    Context context = parent.getContext();
    LayoutInflater inflater = LayoutInflater.from(context);
    View view = inflater.inflate(R.layout.movie_item,parent,false);

    return new MovieViewHolder(view);

}

@Override
public void onBindViewHolder(final MovieViewHolder holder, int position) {

   Movie movie = movieList.get(position);

   holder.mv_name.setText(movie.getName());



    class ImageDownloadTask extends AsyncTask<String,Void,Bitmap>{
       @Override
       protected Bitmap doInBackground(String... strings) {
           Bitmap bitmap = null;
           URL url = createUrl(strings[0]);

           Log.v("stringurl",strings[0]);


           try {
               bitmap = makeHttpRequest(url);

           } catch (IOException e) {

           }

           return bitmap;
       }

        @Override
        protected void onPostExecute(Bitmap bitmap) {



            holder.mv_img.setImageBitmap(bitmap);
        }

        private URL createUrl(String StringUrl){
           URL url = null;

           try {
               url = new URL(StringUrl);
           } catch (MalformedURLException e) {
               return null;
           }

           return url;
       }

       private Bitmap makeHttpRequest(URL url) throws IOException{
           HttpURLConnection urlConnection = null;
           InputStream stream = null;
           Bitmap bitmap = null;
           try {
               urlConnection = (HttpURLConnection) url.openConnection();
               urlConnection.setRequestMethod("GET");
               urlConnection.setConnectTimeout(10000);
               urlConnection.setReadTimeout(15000);
               urlConnection.connect();

               stream = urlConnection.getInputStream();
               bitmap = BitmapFactory.decodeStream(stream);
               //Log.v("image:",bitmap.toString());
               return bitmap;



           }

           catch (IOException e){

           }

           finally {
               if (urlConnection != null) urlConnection.disconnect();
               if (stream != null) stream.close();
           }

           return bitmap;

       }
   }
    new ImageDownloadTask().execute(movie.getImg());


}


@Override
public int getItemCount() {
    return movieList == null ? 0 : movieList.size();
}

class MovieViewHolder extends RecyclerView.ViewHolder{
   ImageView mv_img;
   TextView mv_name;

   public  MovieViewHolder(View itemView){
       super(itemView);

       mv_img = (ImageView) itemView.findViewById(R.id.mv_img);
       mv_name = (TextView) itemView.findViewById(R.id.mv_name);


   }
}
}

虽然向下滚动图像正在加载其他电影的图像 displaying.For 例如,对于一部电影,正在显示另一部电影图像,一秒钟后也会显示另一部电影图像,以这种方式在正在显示一系列不同的图像正确的图像。

我正在从 Url 下载图像,我从 inBindViewHolder 方法的响应中获得。 如何解决这个问题?

问题

您的问题的根本原因是位图是在视图回收后检索的,因此在您使用它时会出现不匹配。

如何解决

  • 简短的回答是使用像 Picasso or Glide 这样的图像缓存库。这些库旨在完全满足您的需求。
  • 另一种选择是尝试自己完成。您可以做的是将 URL 保存在 holder 中,仅当当前 URL 与您刚刚获取的匹配时才调用 setImageBitmap() 。要保存 URL,只需在 MovieViewHolder 中添加一个 URL 字段并在每次检索图像时存储 URL 并在完成下载时检查它是否匹配。

问题

这里的事情是要意识到 ViewHolder 是重用对象的池,当您滚动时,重用的 ViewHolder 将出现,并且将显示之前加载的图像。

通过使用 Picasso 或 Glide 或类似软件,您还可以使用缓存和效果等附加功能节省大量代码。

解决方案

首先你可以使用 Picasso 这样的库

compile 'com.squareup.picasso:picasso:2.5.2'

然后在你的 recyclerview 中绑定 viewholder

Picasso.with(holder.imageView.getContext()).cancelRequest(holder.imageView);
Picasso.with(holder.imageView.getContext()).load("http://image.com/image.png").into(holder.imageView);

第一行代码将停止加载之前的所有图像。 第二行将加载当前图像。

用您的图片 url 替换 "http://image.com/image.png"。它需要字符串,URL,等等...

了解更多关于毕加索的信息here

我也搜索过此解决方案,并从 Doron Yakovlev-Golani 的回答中为自己制定了一个解决方案,因为我的声誉很低,所以我无法添加评论。下面是我的解决方案,这里当我在 ImageView 中添加图像时,我还向 ImageView 添加了一个 ContentDescription 作为参考,以供将来确定调用 ViewHolder 时需要显示哪个图像。 ContentDescription 是作为字符串的当前 ListView 位置。 这里有两个条件,第一个用于检查以前是否添加过图像,如果以前没有添加图像,我添加了图像。第二个图像已经添加到 ImageView 中,所以我通过调用 ImageView ContentDescription 检查需要加载哪个图像,如果 ContentDescription 与当前位置匹配,则意味着我需要将当前位置图像从我的列表添加到 ImageView。

在您的 onViewHolder 中,您可以这样使用:

//checking it is first time or not
    if (holder.mv_img.getContentDescription() == null) {
        //adding current position for loading current position image
        imageView.setContentDescription(position + "");
    }
    if (holder.mv_img.getContentDescription().equals(position + "")) {
        holder.mv_img.setImageBitmap(userLogoUri);
    }

使用Picasso or Glide Library to display images in RecyclerView