15

I have a GridView in android which I fill it with data retrieved from a xml resource.
For example I have 15 items in the GridView which are placed in order. The overall height exceeds the Screen height so i have to scroll to see the rest of the items.
The problem is when I scroll back up, the order of the invisible rows have changed. It's a mysterious behavior as sometimes items swap rows with each other. Here is my getView method:

public class ImageAdapter extends BaseAdapter {
        public ImageAdapter(Context c, NodeList cuu) {
                cu = cuu;
        }
        public int getCount() {
                Log.d("Node Count",cu.getLength()+"");
                return cu.getLength();
        }
        public Object getItem(int position) {
                return position;
        }
        public long getItemId(int position) {
                return position;
        }
        public View getView(int position, View convertView, ViewGroup parent) {
                View myView = convertView;
                if (convertView == null) {
                    Node nd = cu.item(position);
                    Log.d("nodes","Pos: "+(position)+" Name: "+nd.getNodeName()+" Title: "+nd.getAttributes().getNamedItem("title").getTextContent());
                    int catID = Integer.parseInt(nd.getAttributes().getNamedItem("id").getTextContent());
                    LayoutInflater li = getLayoutInflater();
                    myView = li.inflate(R.layout.grid_item, null);
                   ImageView imageView = (ImageView) myView.findViewById(R.id.grid_item_image);
                   myView.setLayoutParams(new GridView.LayoutParams(70, 100));
                   id.download(nd.getAttributes().getNamedItem("icon").getTextContent(),imageView);
                   TextView textView = (TextView) myView.findViewById(R.id.grid_item_text);
                   textView.setText(nd.getAttributes().getNamedItem("title").getTextContent());
                   myView.setTag((Object) catID);
                }else{
                    //Log.d("nodes","Pos: "+(position));
                }
                return myView;
        }
        private NodeList cu = null;
    }

Update: Well, it's rather odd. After some more debugging I noticed that in the GridView, the Adapter skips the 13th position, meaning it returns 1 instead of 13 and then moves on to 14!!! (I guess the 13 is bad luck!)

2hamed
  • 8,719
  • 13
  • 69
  • 112

6 Answers6

11
public View getView(int position, View convertView, ViewGroup parent) {
    View view;
    if (convertView == null) {
        view= inflate your xml
    } else {
        view=convertView;
    }
    // all remaining code like 
    // view.findViewById(R.id.btn).setText("MyButton");                            
    // must be outside if-else
}
lopez.mikhael
  • 9,943
  • 19
  • 67
  • 110
Abhijit Kurane
  • 834
  • 15
  • 20
8

If that is all the code you have in the getView method you're not implementing it right:

public View getView(int position, View convertView, ViewGroup parent) {
        View myView = convertView;
        if (myView == null) {           
            Node nd = cu.item(position);
            int catID = Integer.parseInt(nd.getAttributes().getNamedItem("id")
                    .getTextContent());
            LayoutInflater li = getLayoutInflater();
            myView = li.inflate(R.layout.grid_item, null);
            myView.setLayoutParams(new GridView.LayoutParams(70, 100));         
            myView.setTag((Object) catID);
        } 
        Node nd = cu.item(position);
        Log.d("nodes", "Pos: " + (position) + " Name: " + nd.getNodeName()
                + " Title: "
                + nd.getAttributes().getNamedItem("title").getTextContent());
        ImageView imageView = (ImageView) myView
                .findViewById(R.id.grid_item_image);
        id.download(nd.getAttributes().getNamedItem("icon")
                .getTextContent(), imageView);
        TextView textView = (TextView) myView
                .findViewById(R.id.grid_item_text);
        textView.setText(nd.getAttributes().getNamedItem("title")
                .getTextContent());
        return myView;
    }

I don't know if the code above works, yours is a bit strange. Anyway, I think the behavior you see its normal because all you do in your adapter is populating the first visible elements and then the adapter will be reusing the exact same elements when you scroll up and down because of the recycling. In the getView you should:

  • Check if the convertView is null:
    • If it is null it's time to inflate a new View for this GridView's element. You could also use the holder pattern to cache looking for the composing Views(instead of searching with findViewById everytime)(You use the setTag element for the inflated View but it's a piece of data from the Node data element ?!? What do you plan to do with it?!?)
    • If it isn't null you'll do nothing(or if you implement the holder pattern you would get the tag with the already searched Views)

And this is what you should do in that if/else statement

  • After the part above you'll populate the Views with data(so they hold the apropriate data for that position).
user
  • 86,916
  • 18
  • 197
  • 190
4

I have just deleted the

if(convertView==null)

it works

Boris Karloff
  • 1,190
  • 12
  • 20
3

Your adapter implementation is fatally flawed.

In getView(), if convertView is null, you inflate a layout and populate its widgets. This is fine.

In getView(), if convertView is not null, you do absolutely nothing. This is exceedingly wrong.

What you should be doing in getView(), if convertView is not null, is still populating the cell's widgets. convertView represents a cell to be recycled, so you can skip the inflation and save CPU time, but you still have to update that cell's widgets to reflect whatever position you are supposed to be setting up in this specific getView() call.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • im having the same problem but i applied ViewHolder, and still my order of images were changing. – Mikey Nov 02 '12 at 09:42
  • @CommonsWare Is it true that all actions including `findViewById()` must be done outside if/else? Someone stated that here and this information is new to me. – sandalone Aug 18 '13 at 12:44
  • 1
    @sandalone: On **every call to `getView()` you need to configure the row**. What `if`/`else` constructs you use, if any, is up to you, so long as that on very call to `getView()` you completely configure the row. In the case of the OP, the OP was *not* configuring the row if `convertView` was not `null`. – CommonsWare Aug 18 '13 at 12:59
1

If your Grid item has several views in it you can use getTag() and setTag() methods. In this case, grid items won't change their places on scrolling anymore and the performance still be fine:

public class SomeAdapter extends BaseAdapter {

    public static class ViewHolder {
        public TextView tvTitle;
        public ImageView imgPoster;
    }

    //...
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder grid;
        LayoutInflater inflator = activity.getLayoutInflater();

        if (convertView == null) {
            grid = new ViewHolder();
            convertView = inflator.inflate(R.layout.grid_item, null);
            grid.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
            grid.imgPoster = (ImageView) convertView.findViewById(R.id.img_poster);

            convertView.setTag(grid);   // <<-- H E R E
        } else {
            grid = (ViewHolder) convertView.getTag();   // <<-- H E R E
        }
        grid.tvTitle.setText(dataItem.getTitle());
        grid.imgPoster.setImage(dataItem.getImage());
        return convertView;
    }
}
careful7j
  • 799
  • 9
  • 20
0

I used this solution, based on another samples, and worked:

public View getView(int position, View convertView, ViewGroup parent) {
    View view = null;
    if (convertView == null) {
        view = inflate your xml and apply the View Holder pattern
    } else {
        view = convertView;
    }
    // retrieve the object by Holder pattern 
    // extra code here
}
edwindh
  • 99
  • 1
  • 4