1

I'm using addFooterView to add a footer view to a ListView, which is populated by a CursorAdapter controlled by Loader. Sometimes the ListView tries to recycle the footer view however (through CursorAdapter.bindView). This causes either ClassCastException (if I allow the recycle) or some item views shown as footer view (if I do not allow the recycle).

If I understand it right, the footer views added by addFooterView are not supposed to be recycled ("Footer views are special views at the bottom of the list that should not be recycled during a layout"). So this is probably a bug in Android APIs.

Is there any way to work around this problem? What is the correct way to add footer views to a ListView populated by CursorAdapter?


Some relevant code:

In the activity:

paletteView = (ListView)findViewById(R.id.palette);
paletteView.addFooterView(new PaletteAdapter.NewSlot(this));
paletteAdapter = new PaletteAdapter(this, null);
paletteView.setAdapter(paletteAdapter);
getLoaderManager().initLoader(0, null, this);

In the adapter (PaletteAdapter):

@Override public void
bindView(View view, Context context, Cursor cursor)
{
  if (view instanceof NewSlot)
    {
      Log.wtf(TAG, 
              ("Recycle NewSlot to ID "
               + cursor.getLong(cursor.getColumnIndex
                                (DataProvider.Palettes._ID))));
      return;
    }
  final Slot slot = (Slot)view;
  // Blah blah...
}
Yuhta
  • 168
  • 2
  • 8

2 Answers2

1

Worked it out by myself.

Thanks to this answer, I overrode the getView function as following and everything works well. Thanks again to Abhinav. I should look more into the source code when having problems.

@Override public View
getView(int position, View convertView, ViewGroup parent)
{
  if (convertView instanceof NewSlot)
    return super.getView(position, null, parent);
  else return super.getView(position, convertView, parent);
}
Community
  • 1
  • 1
Yuhta
  • 168
  • 2
  • 8
0

Just in case it helps anyone else, I had the same symptom (where the listview was trying to recycle the footer view), and the reason for this is that I was updating the height of the footer view with this code:

 private void setFooterViewHeight(int height) {
    LayoutParams layoutParams = new ListView.LayoutParams(LayoutParams.MATCH_PARENT, height);
    mFooterView.setLayoutParams(layoutParams);
 }

What I didn't realise is that the ListView.LayoutParams is where the viewType is cached, and when I create a new LayoutParams, it's being reset to 0, which means that it's eligible for the view recycle process

What I have now instead is:

private void setFooterViewHeight(int height) {
    LayoutParams layoutParams = mFooterView.getLayoutParams();
    if(layoutParams == null) {
        layoutParams = new ListView.LayoutParams(LayoutParams.MATCH_PARENT, height, ListView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER);
        mFooterView.setLayoutParams(layoutParams);
    } else {
        layoutParams.height = height;
        mFooterView.requestLayout();
    }
}
jtlim
  • 3,861
  • 1
  • 16
  • 14