1
votes

I have some weird events occurring in getView() method in custom adapter for listview. It seems as if cached views are only updated during app's end. I've read a bunch of tutorials, but never seen an issue like this.

When I add first item to an adapter, everything is fine - convertView is null, I inflate view and return it. However, when I try adding second item, getView() gets sent exactly the same convertView, for position 0 and 1 (even though for position 1 it should be null), resulting in identical items.

After restarting app, every added item is viewed properly (data is serialized), but trying to add more items still results in views identical to the first one.

I'm sure the problem lays in adapter, getView(), because when I stop using convertView and just inflate items every single time, it works perfectly fine.

This is how my methods look like. mNames is Vector; when it changes, it's serialized and the adapter is notified. This vector sets adapter count (see getCount). It's deserialized in onCreate(), right before being passed to adapter.

@Override
    public int getCount() {
        return mNames.size();
    }

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if(convertView == null) {
        convertView = layoutInflater.inflate(R.layout.grouplist_listview_item, null);

        //just saying, there are more subviews; I didn't find it relevant
        ((TextView)convertView.findViewById(R.id.grouplist_listview_item_text)).setText(mNames.elementAt(position));
    }
    return convertView;
}

So I don't really understand two things here:

  • Why all getView() calls are made with the same convertView?
  • Why they aren't sent like this during app start and it works then?
1
move ((TextView)convertView.findViewById(R.id.grouplist_listview_item_text)).setText(mNames.elementAt(position)); outside the if - Blackbelt
Wow... That was fast and correct. Thank you! - Maciej Dziuban
As a note on the side: you really hurt the performance of this thing by doing findViewById every thime you run getView. You should use the Viewholder pattern (developer.android.com/training/improving-layouts/smooth-scrolling.html). - fweigl
Oh yeah, forgot to mention, that I am aware of it; I just didn't want to complicate the posted example. Thanks, though! - Maciej Dziuban
getview() is called to tell the adapter hey a need what needs to be in this view for this position. This gets fired every time you either want to fire it or a new view is shown. I think the view will be null until the adapter is full then its just reusing the views changing whats in them according to what position its at. - Xjasz

1 Answers

0
votes

I think you need to read a good tutorial. I know good webpage @ Using an ArrayAdapter with ListView. Search text for "Defining the Adapter" to see the getView() code.

Code snippet:

    @Override
    public View getView(int position, @Nullable View convertView, ViewGroup parent) {
       // Get the data item for this position
       User user = getItem(position);    
       // Check if an existing view is being reused, otherwise inflate the view
       if (convertView == null) {
          convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_user, parent, false);
       }
       // Lookup view for data population
       TextView tvName = (TextView) convertView.findViewById(R.id.tvName);
       // Populate the data into the template view using the data object
       tvName.setText(user.name);
       // Return the completed view to render on screen
       return convertView;
    }

Note: The code uses setText method. This will test your code with the ArrayAdapter and your layout.