2

I have a list view with 14 rows, with each item as View Pager. Here is my getView() Method:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        FindMyBeerPager findMyBeerPager;
        if(convertView==null){
            holder = new ViewHolder();
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.beer_list_item, parent,false);

            findMyBeerPager = new FindMyBeerPager(context, findBeerDataList.get(position));
            holder.beerPager = (ViewPager)convertView.findViewById(R.id.mypager);
            holder.beerPager.setAdapter(findMyBeerPager);

            System.out.println("Recycling view position"+position);
            holder.beerPager.setTag(findMyBeerPager);

            convertView.setTag(holder);
        }
        else{
            holder = (ViewHolder) convertView.getTag();
            System.out.println("Recycled"+position);
        }

        return convertView; 
    }
}

class ViewHolder{
    ViewPager beerPager;
}

Problem: The problem I am facing is that, when I scroll down the list view I am not getting further rows values,i.e the list view is recycled with the previous values. I don't know why this is going on. I have to send the View Pager (data item for every position). Before Scrolling down everything works fine.

afuzzyllama
  • 6,538
  • 5
  • 47
  • 64
Gaurav Arora
  • 8,282
  • 21
  • 88
  • 143

3 Answers3

3

Change getView to

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        FindMyBeerPager findMyBeerPager;
        if(convertView==null){
            holder = new ViewHolder();
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.beer_list_item, parent,false);
            holder.beerPager = (ViewPager)convertView.findViewById(R.id.mypager);
            convertView.setTag(holder);
        }
        else{
            holder = (ViewHolder) convertView.getTag();
            }

         findMyBeerPager = new FindMyBeerPager(context, findBeerDataList.get(position));
             holder.beerPager.setTag(findMyBeerPager);
             holder.beerPager.setAdapter(findMyBeerPager);
        return convertView; 
    }
}

You can move LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); to the constructor of adapter class.

Also use Log for logging instead of System.out.println

How ListView's recycling mechanism works

ViewPager and OnItemClickListener in ListView

Check the answer by Dianne Hackborn in the above link.

Community
  • 1
  • 1
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • I know this solution, but with this solution does not works smoothly, as everytime adapter is being set – Gaurav Arora Nov 23 '13 at 06:38
  • @GauravArora list view recycles views and that is the reason you don't see anything when you scroll. If you want data to display in lisview you need to set it everytime. – Raghunandan Nov 23 '13 at 06:40
  • @GauravArora http://stackoverflow.com/questions/11945563/how-listviews-recycling-mechanism-works – Raghunandan Nov 23 '13 at 06:42
  • I understand you, but setting the adapter again and again is making listview hard to scroll even. Or can you please tell me another way to add view pager as each item in list view ? – Gaurav Arora Nov 23 '13 at 06:48
  • @GauravArora view pager is not intended to work that way http://stackoverflow.com/questions/8164485/viewpager-and-onitemclicklistener-in-listview/8548580#8548580. check Dianne hackborn answer. So you need to think of a alternative – Raghunandan Nov 23 '13 at 06:51
  • @Raghynandan. I appreciate your answer, but will horizontal scrollview be helpful to make the same effect as a view pager will do in list view ? – Gaurav Arora Nov 23 '13 at 06:53
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/41751/discussion-between-raghunandan-and-gaurav-arora) – Raghunandan Nov 23 '13 at 06:54
  • 1
    I have finally resolved my problem with the help of the View Flipper. Thanks – Gaurav Arora Nov 30 '13 at 06:20
  • Thanks @Raghunandan for all your cooperation. – Gaurav Arora Nov 30 '13 at 07:06
1

Can you try setting the adapter in the esle block?

  @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        FindMyBeerPager findMyBeerPager;
        if(convertView==null){
            holder = new ViewHolder();
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.beer_list_item, parent,false);

            holder.beerPager = (ViewPager)convertView.findViewById(R.id.mypager);

            System.out.println("Recycling view position"+position);
            holder.beerPager.setTag(findMyBeerPager);

            convertView.setTag(holder);
        }
        else{
            holder = (ViewHolder) convertView.getTag();
            System.out.println("Recycled"+position);
            findMyBeerPager = new FindMyBeerPager(context, findBeerDataList.get(position));
            holder.beerPager.setAdapter(findMyBeerPager);
        }

        return convertView; 
    }
}
Quentin DOMMERC
  • 876
  • 1
  • 8
  • 24
1

It can work without setting parameter on every getView(), but for that you need to extend BaseAdapter and overload following methods:

@Override
public boolean hasStableIds() {
    return true;
}

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

@Override
public long getItemId(int position) {
    return position;
}

@Override
public int getItemViewType(int position) {
    return position;
}

@Override
public int getViewTypeCount() {
    return MAXIMUM_NUMBER_OF_ITEMS_IN_LIST_VIEW;
}

In this way BaseAdapter will keep in recycler separate view for every element. It's good solution for short lists with custom views inflated for each item. (but can work also when inflated views are the same)

Notice that getViewTypeCount() is invoked only once on constructor, so BaseAdapter must know then how many items your list will have.

Crucial for the idea is getItemViewType() returning different value for each item. Thanks to that getView() will be getting unique convertView for every list item.

Then you can completely skip condition (convertView != null) and put all code into (convertView == null){}

Malachiasz
  • 7,126
  • 2
  • 35
  • 49
  • @Makachiasz. Excellent answer, but when I set my getViewTypeCount as arraylist.size(); , then it gives me exception - "getViewCount" cannot be less than 1. And if I hard code my ViewCount Value then it runs OK. I donot want to hardcode it. Please tell me the means to do the same – Gaurav Arora Nov 27 '13 at 16:31
  • Did you understand my problem ? – Gaurav Arora Nov 27 '13 at 16:39
  • As I wrote getViewTypeCount() must be hardcoded, because it's used internally in constructor of BaseAdapter for creating array of views (View views[getViewTypeCount()]). So alternatively you can try passing value of MAXIMUM_NUMBER_OF_ITEMS_IN_LIST_VIEW; at the beginning of BaseAdapter constructor (before super). Personally I have MAXIMUM_NUMBER_OF_ITEMS_IN_LIST_VIEW = 100 and I never have more items. This number shouldn't be too big, because Views array consumes memory. Even empty views. – Malachiasz Nov 27 '13 at 16:52
  • Its ok. Then this solution will not be helpful to me, as I donot have the fixed number of values. Thanks – Gaurav Arora Nov 27 '13 at 16:53
  • But if you know what is your maximum number of values and it's not very big then you can hardcode it. The number of getViewTypeCount() can be bigger that the number of items in ListView. – Malachiasz Nov 27 '13 at 16:56
  • No @Malachiasz, it is not fixed at all, can be any. Thanks – Gaurav Arora Nov 27 '13 at 17:51
  • Although it was a nice answer. I want to give you 50 for this, but will wait for any another answer to come – Gaurav Arora Nov 27 '13 at 17:51
  • @GauravArora If you don't want to hardcode the value for `MAXIMUM_NUMBER_OF_ITEMS_IN_LIST_VIEW`, change it to some static integer (defined in your activity) which you can initialize to `findBeerDataList.size()` **before** initializing the adapter. Then `return YourActivity.the_static_constant;` – Vikram Nov 27 '13 at 18:16
  • yeah, of course you can use some value initialized before creating the adapter. It's similar way to what I wrote: "alternatively you can try passing value of MAXIMUM_NUMBER_OF_ITEMS_IN_LIST_VIEW; at the beginning of BaseAdapter constructor (before super).". The thing is that the number of elements cannot change after adapter is created. – Malachiasz Nov 28 '13 at 08:47