1

Iam having a ViewHolder class like this

    static class ViewHolder {
    protected String fileName;
    protected Bitmap bitmap = null;
    protected CheckBox checkBox;
    protected int position;
    protected int resourceId = 0;
    protected ImageView imageView;
    protected TextView textView;
}

and within my getView()

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final ViewHolder viewHolder;

    if(convertView != null)
    {
        ViewHolder holder = (ViewHolder) convertView.getTag();
        if(!holder.fileName.equals(fileList.get(position)))
            convertView = null;
    }
    if(convertView == null)
    {
        convertView = inflater.inflate(R.layout.image_layout, null, false);
        viewHolder = new ViewHolder();

        viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageView);
        viewHolder.textView = (TextView) convertView.findViewById(R.id.text);

        // Set viewHolder attributes
        viewHolder.position = position;
        viewHolder.fileName = fileList.get(position);;

        // set the checkbox
        viewHolder.checkBox = (CheckBox) convertView.findViewById(R.id.checkBox);

        // Set the path of the file
        final String filePath = context.getBasePath(position);

        if(new File(filePath).isDirectory())
        {
            viewHolder.imageView.setImageResource(R.drawable.folder);
            viewHolder.resourceId = R.drawable.folder;
        }
        else
        {
            String mimeType = Utility.getMimeType(filePath);
            if(mimeType.contains("image"))
            {
                loadImage(viewHolder, viewHolder.imageView, filePath);
            }
            else
                viewHolder.resourceId = handleFile(viewHolder.imageView, filePath);
        }
        convertView.setTag(viewHolder);
    }
    else
    {
        viewHolder = (ViewHolder) convertView.getTag();

        if(viewHolder.bitmap == null)
            viewHolder.imageView.setImageResource(viewHolder.resourceId);
        else
            viewHolder.imageView.setImageBitmap(viewHolder.bitmap);
    }

    viewHolder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton checkBox, boolean checked) {
            viewHolder.checkBox.setChecked(checked);
            listener.onFileStateChanged(viewHolder.position, checked);
        }
    });

    // set the fileName
    viewHolder.textView.setText(viewHolder.fileName);

    if(checkBoxVisibility)
        viewHolder.checkBox.setVisibility(View.VISIBLE);
    else
        viewHolder.checkBox.setVisibility(View.INVISIBLE);

    return convertView;
}

And at this time the when i refresh the Adapter using notifydatasetChanged() without changing data, the ViewHolder that i get by calling getTag() was returning wrong tags. It was working like

If the position is 1 the holder object was of the view at position 0. ie; the previous object was returned..

Atlast I found a post

which is not the same but with the same method and the solution works for me .. I don't know how ..

The Solution was

setting the width of ListView to MATCH_PARENT in xml, In the post it was height.

Does any one know , What is the reason for such a behaviour ? There is no logic that i can find behind this issue

Community
  • 1
  • 1
Viswanath Lekshmanan
  • 9,945
  • 1
  • 40
  • 64

1 Answers1

1

Seems that when you don't use this workaround, Android has to resize the listview's layout several times until it's performed. That's why there's many users complaining about getView() being called more times than it "should".

Anyway, be conscious that getView() is not called secuentially, it's called in the order that Android determines, so don't expect to be tags shown in order.

--- EDIT ---

And here comes the confirmation, page 48. Hope this helps!

nKn
  • 13,691
  • 9
  • 45
  • 62
  • I don't know the accurate explaination of this, but my guess is that when the width is set to `MATCH_PARENT` (as it actually should), Android has already the layout rendered properly, so it's called sequentially because Android sees each row equally "hard" to render. On the other hand, when set to `WRAP_CONTENT`, additionally to displaying the layout, each row has to be rendered to the definite layout and Android processes the `getView()` as soon as it renders each row, and that means each one doesn't have to be equal to render, that's why it's not sequential. – nKn Jan 23 '14 at 09:02
  • 1
    Thanks for trying to help me out and explaining what you know, may be that, but iam looking for some exact solution, because this is what we normally work on every program, So i dont want to do it without knowledge – Viswanath Lekshmanan Jan 23 '14 at 09:05
  • 1
    I've just found this: http://dl.google.com/googleio/2010/android-world-of-listview-android.pdf on page 48 there's a bit about it. It's a pity it's now detailed a bit more but gives an idea. – nKn Jan 24 '14 at 11:34
  • Yeah, Thats great... There assumptions should be documented :( How do we know if its like this ??? – Viswanath Lekshmanan Jan 24 '14 at 11:55
  • 1
    Indeed, the funny thing is that I found this looking for a complete different subject :-) I'll keep that page though, hope at least other users might help your question (I upvoted it) – nKn Jan 24 '14 at 11:59