Reputation: 417
I am facing an unexpected problem in inflating listview.
I am creating a listview in which I am showing image title and thumbnail. We can also show audio files thumbnail but giving class of only image.
When I scroll list speedily. Its view changed many times. Below my adapter class in which I am using an AsynkTask class to get thumbnail and set this thumbnail to imageview.
public class AdapterForBooks extends ArrayAdapter<ModelFile> {
List<ModelFile> list;
Context context;
WindowManager wm;
Display display;
int w;
public AdapterForBooks(Context context, List<ModelFile> list) {
super(context, R.layout.list_layout_home, list);
// TODO Auto-generated constructor stub
this.list = list;
this.context = context;
wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
display = wm.getDefaultDisplay();
w = display.getWidth();
}
static class ViewHolder {
TextView txtName;
ImageView img;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
View view = null;
if (convertView == null) {
LayoutInflater inflter = (LayoutInflater) LayoutInflater
.from(context);
view = inflter.inflate(R.layout.list_layout_home, null);
final ViewHolder holder = new ViewHolder();
holder.txtName = (TextView) view
.findViewById(R.id.textViewName);
holder.img = (ImageView) view.findViewById(R.id.imageView);
LayoutParams params = (LayoutParams) holder.img
.getLayoutParams();
params.height = w / 4;
params.width = w / 4;
holder.img.setLayoutParams(params);
view.setTag(holder);
} else {
view = convertView;
}
final ViewHolder holder = (ViewHolder) view.getTag();
String name = list.get(position).getFileName();
holder.txtName.setText(name);
String filePath = list.get(position).getFilePath();
// holder.img.setImageBitmap(Bitmap.createScaledBitmap(BitmapFactory.decodeFile(filePath),100,100,false));
new SetThumbnail()
.execute(new Thumbnail(holder, filePath, position));
return view;
}
class Thumbnail {
ViewHolder holder;
String path;
int position;
public Thumbnail(ViewHolder holder, String path, int position) {
this.holder = holder;
this.path = path;
this.position = position;
}
public ViewHolder getHolder() {
return holder;
}
public String getPath() {
return path;
}
public int getPosition() {
return position;
}
}
class SetThumbnail extends AsyncTask<Thumbnail, Void, Bitmap> {
ViewHolder holder;
int position;
@Override
protected Bitmap doInBackground(Thumbnail... params) {
// TODO Auto-generated method stub
int pos = params[0].getPosition();
position = pos;
String path = params[0].getPath();
holder = params[0].getHolder();
Log.e("Ref", "Pos = " + pos + " " + holder);
try {
Bitmap thumbnail = BitmapFactory.decodeFile(path);
thumbnail = Bitmap.createScaledBitmap(thumbnail, 100, 100,
false);
return thumbnail;
} catch (Exception e) {
return null;
}
}
@Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if (holder != null && result != null) {
Log.i("Ref", "Position = " + position + " " + holder);
holder.img.setImageBitmap(result);
} else {
holder.img.setImageResource(R.drawable.format_picture);
}
}
}
}
I can also set thumbnail by the help of commented line before starting asynktask but it will slow my list inflation.
Upvotes: 1
Views: 108
Reputation: 1525
As I suspect, you are downloading images from internet to set in your imageviews. The images change or shuffle because of lazy loading, it means that your imageViews get created before the image is downloaded and while you scroll android set the downloaded images in the first imageview it finds. The imageview it find might be wrong because in getview method in adapter reuse memory allocated to objects and this reusability causes images to shuffle.
However, this is a nice project to solve this problem, which I also used and solved mine.
Upvotes: 0
Reputation: 125
first of all declare inflater on class level and in getview only write if condition if view is null then create and run it. it will definitely work.
LayoutInflater inflter = (LayoutInflater) LayoutInflater
.from(context);
......
......
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
if (convertView == null) {
view = inflter.inflate(R.layout.list_layout_home, null);
}
Upvotes: 2
Reputation: 7708
ListView recycles views, when you scroll. Your problem is happening because the AsyncTask
finishes after the view has been recycled, so "old" images are displayed in the recycled views. Here is how you can solve it:
Step 1) Update your get view to include a line just before starting the AsyncTask
holder.img.setTag(new Integer(position))
new SetThumbnail().execute(new Thumbnail(holder, filePath, position));
Step 2) Set the image only if the position is same as the tag (update your onPostExecute
):
@Override
protected void onPostExecute(Bitmap result) {
if(holder == null) return;
int viewPosition = (Integer) holder.img.getTag();
if(position == viewPosition) {
if(result != null) {
holder.img.setImageBitmap(result);
}
else {
holder.img.setImageResource(R.drawable.format_picture);
}
}
}
Upvotes: 1