I have an adapter that wraps a CursorAdapter
, the reason being that I need to display items in rows (as in a GridView
) but also display detail about each item if clicked in a panel below (requiring a ListView
). So instead of a CursorAdapter
directly populating the ListView
, I have an inner adapter:
public class ChallengeAdapter extends BaseAdapter {
class ChallengeDataAdapter extends CursorAdapter {
private BaseAdapter mChallengeAdapter;
public ChallengeDataAdapter(Context context, Cursor cursor, BaseAdapter a) {
super(context, cursor, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
mChallengeAdapter = a;
}
@Override
public void bindView(View arg0, Context arg1, Cursor arg2) {
// TODO Auto-generated method stub
}
@Override
public View newView(Context arg0, Cursor arg1, ViewGroup arg2) {
// TODO Auto-generated method stub
return null;
}
@Override
protected void onContentChanged() {
super.onContentChanged();
mChallengeAdapter.notifyDataSetChanged();
}
}
private ChallengeDataAdapter mDataAdapter;
public ChallengeAdapter(Context context, Cursor cursor) {
mDataAdapter = new ChallengeDataAdapter(context, cursor, this);
}
@Override
public int getCount() {
return (mDataAdapter.getCount() + ChallengeMultiTile.ROW_SIZE - 1) / ChallengeMultiTile.ROW_SIZE; //integer divide rounds down
}
@Override
public Object getItem(int position) {
Challenge[] output = new Challenge[ChallengeMultiTile.ROW_SIZE];
int min = position * ChallengeMultiTile.ROW_SIZE;
int max = Math.min(position * ChallengeMultiTile.ROW_SIZE + ChallengeMultiTile.ROW_SIZE, mDataAdapter.getCount());
for(int i=min; i<max; ++i) {
output[i-min] = Challenge.get((Cursor) mDataAdapter.getItem(i));
}
return output;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null) {
convertView = new ChallengeMultiTile(parent.getContext());
}
((ChallengeMultiTile) convertView).populate((Challenge[]) getItem(position));
convertView.setBackgroundColor(0xfffffff);
return convertView;
}
public void swapCursor(Cursor cursor) {
mDataAdapter.swapCursor(cursor);
notifyDataSetChanged();
}
}
This works briefly, but then the ChallengeDataAdapter
starts to have a getCount()
of zero. However, I put a breakpoint there and ChallengeDataAdapter#mCursor.getCount()
is 6. I trapped this in the onContentChanged()
method but I don't know for sure that's where it's happening.
Why would a CursorAdapter
give a count of zero when its inner cursor gives a count of six?
When you look at the CursorAdapter source code you'll see the following for getCount() and onContentChanged():
public int getCount() {
if (mDataValid && mCursor != null) {
return mCursor.getCount();
} else {
return 0;
}
}
protected void onContentChanged() {
if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {
if (false) Log.v("Cursor", "Auto requerying " + mCursor + " due to update");
mDataValid = mCursor.requery();
}
}
So while mCursor.getCount() might return 6, getCount() might return 0 if the requery failed. Why the requery fails is another question and not one I could answer from the code you posted.
BTW you don't need to keep a reference to the ChallengeAdapter in your ChallengeDataAdapter class. ChallengeDataAdapter is an inner class which is associated with an instance of its enclosing class and has direct access to that object's methods and fields. Instead of calling mChallengeAdapter.notifyDataSetChanged() you could just do a ChallengeAdapter.this.notifyDataSetChanged();