I have one db table like this:
ID
NAME
COUNTRY_NAME
And i want a list like this:
+ Italy
- Potato
- Tomato
+ France
- Fromage
- Baguette
And i wrote a CursorAdapter that, every time requery is called, read ALL items on the table and map it in a object that is used to map position of every item (real item or header).
private static class PersonEntry {
boolean isHeader;
String countryName;
int realPos;
int id;
}
Code is this:
/* cursor generated by querying whole table */
public void readHeaders(Cursor cursor ) {
Log.d(this.getClass().getSimpleName(),"readHeaders init");
items = new ArrayList<PersonEntry >();
this.mCursor = cursor;
cursor.moveToFirst();
int i = 0;
String previousCountry = "";
String currentCountry;
while(cursor.isAfterLast() == false) {
int id = cursor.getInt(cursor.getColumnIndexOrThrow(Match.ROW_ID));
currentCountry = cursor.getString(cursor.getColumnIndexOrThrow(Person.ROW_COUNTRY_NAME));
if (!currentCountry.equals(previousCountry)) {
// ho incontrato una nuova nazione
// rispetto alla precedente, aggiungiamola
items.add(new PersonEntry(... define isHeader=true ..));
}
// stiamo comunque scorrendo gli elementi, aggiungiamo quello appena trovato
items.add(new PersonEntry( ... defile isHeader = false ....);
previousCountry = currentCountry;
i++;
cursor.moveToNext();
}
cursor.close();
Log.d(this.getClass().getSimpleName(),"readHeaders end");
}
So i rewrote getView, bindView and newView to inflate the right layout and binding the view basing it on realPos-position Cursor.
The method works but it is REALLY expensive: it need to elaborate the whole table and i have got many records. What i am searching for is a simply method to map realPosition -> fakePosition while scrolling the ListView, but methods i thinked are too much complicated and i think that they will break if getView isn't linear (fast scrolling?).
SOLUTIONS: 1) Query ordering by COUNTRY_NAME. While scrolling down real_cursor_position = (requested position - "country changes # (?)"). If the requested position translated in real_position come after a item with a different country_name, it is a header. It will broke when scrolling fist down and after up, i think, unless tricky solutions. ... nothing more
Any other solution?
Edit: Another problem is that i can't predict the number of views returned by adapter.getCount() without scanning the whole table.
I've written the getView
method of simple adapter to show you how you might build a ListView
with headers grouping the items that have the same country. This will assume the header view is in each row's layout showing/hiding it as the current row demands. The same thing could be done by using the getItemViewType
method with a bit more work on binding the various parts of the adapter.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(
R.layout.rowlayout, parent, false);
}
// for simplicity, the header it's just a TextView
TextView header = (TextView) convertView
.findViewById(R.id.headerPart);
// also for simplicity, the row content it's just a TextView
TextView rowText = (TextView) convertView
.findViewById(R.id.normalPart);
// set the data for the row
mCursor.moveToPosition(position);
rowText.setText(mCursor.getString(mCursor.getColumnIndex("name")));
// this is not the first position
if (position - 1 >= 0) {
// if there is a previous position see if it has the same
// country(in which case you already had set the header)
String currentCountry = mCursor.getString(mCursor
.getColumnIndex("country"));
mCursor.moveToPosition(position - 1);
String previousCountry = mCursor.getString(mCursor
.getColumnIndex("country"));
if (currentCountry.equalsIgnoreCase(previousCountry)) {
// the countries are the same so abort everything as we
// already set the header on one of previous rows
header.setVisibility(View.GONE);
} else {
// this is the first occurrence of this country so show the
// header
header.setVisibility(View.VISIBLE);
header.setText(currentCountry);
}
} else {
// this is position 0 and we need a header here
header.setVisibility(View.VISIBLE);
header.setText(mCursor.getString(mCursor
.getColumnIndex("country")));
}
return convertView;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With