RecyclerView显示错误的图像

时间:2018-02-23 15:59:28

标签: android android-recyclerview recycler-adapter android-networking

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

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


   }
}
}

向下滚动图像时正在显示正在显示的其他电影的图像。例如,对于电影,将显示另一个电影图像,并且在第二个之后还显示另一个电影图像,并且在一系列不同的电影图像之后图像正确显示图像。

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

4 个答案:

答案 0 :(得分:3)

<强>问题

这里要认识到ViewHolders是重用对象的池,当你滚动时,将出现一个重用的ViewHolder,并显示之前加载的图像。

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

<强>解决方案

首先,您可以使用像Picasso这样的库

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

然后在您的recyclerview上的bind viewholder

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

第一行代码将停止加载任何先前的图像。 第二行将加载当前图像。

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

了解有关毕加索documentation

的更多信息

答案 1 :(得分:1)

<强>问题

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

如何解决

  • 简短的回答是使用像PicassoGlide这样的图片缓存库。这些库旨在完成你想要完成的任务。
  • 另一种选择是尝试自己做这件事。您可以做的是将URL保存在持有者中并仅在当前URL与您刚刚获取的URL匹配时调用setImageBitmap()。要保存URL,只需在MovieViewHolder中添加一个URL字段,并在检索图像时存储URL,并在完成下载后检查它是否匹配。

答案 2 :(得分:1)

使用PicassoGlide库在RecyclerView中显示图像

答案 3 :(得分:0)

我也一直在寻找这种解决方案,并且从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);
    }