RecyclerView显示错误的图像

问题描述 投票:1回答:3

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

   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中下载图像。如何解决这个问题?

android android-recyclerview recycler-adapter android-networking
3个回答
3
投票

问题

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

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

首先,您可以使用像毕加索这样的图书馆

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

然后在您的recyclerview上查看绑定视图

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等...

了解更多关于Picasso here的信息


1
投票

问题

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

如何解决

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

0
投票

我也搜索了这个解决方案,并且从Doron Yakovlev-Golani回答我为自己做了一个解决方案,因为我的声誉很低,所以我无法添加评论。下面是我的解决方案,这里当我在ImageView中添加一个图像时,我还在ImageView中添加了一个ContentDescription作为参考,以供将来用于确定ViewHolder调用时需要显示哪个图像。 ContentDescription是String的当前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);
    }