The following is the code for the adapter I'm using to display movie items that contain Movie Images and Movie Titles.
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);
}
}
}
While scrolling down images are loading images of other movies are displaying. For example, for a movie, another movie image is getting displayed and after a second also another movie image is getting displayed in that way after a series of different images correct image is getting displayed.
I'm downloading images from the Url I get from the response inBindViewHolder method. How to resolve this issue?
Problem
The thing here is to realize that the ViewHolders are pool of reused objects and as you scroll a reused ViewHolder will appear and the previously loaded in it image will be shown.
By using Picasso or Glide or similar you are saving incredible amount of code also using additional features like cache and effects.
Solution
First you can use a library like Picasso
compile 'com.squareup.picasso:picasso:2.5.2'
then in your recyclerview on bind viewholder
Picasso.with(holder.imageView.getContext()).cancelRequest(holder.imageView);
Picasso.with(holder.imageView.getContext()).load("http://image.com/image.png").into(holder.imageView);
The first line of code will stop any previous images from loading. The second line will load the current image.
Replace "http://image.com/image.png"
with your image url. It takes String, URL, etc...
Read more about Picasso here