Following is my listview adapter classes using AlphabetIndexer. It does not work when I add unicode chars (for hebrew) togather with the english. I get exception in: getSectionForPosition. getting to index -1.... Tries it with 2 entries in the DB - 1 starting with hebrew char (unicode) and one with english. The first char for AlphabetIndexer was the unicode char. Really really need help in this one....
public abstract class RecipeListViewAdapter extends SimpleCursorAdapter implements SectionIndexer
{
protected Context mContext;
protected Cursor mCursor;
private LayoutInflater mInflater;
public static final int TYPE_HEADER = 1;
public static final int TYPE_NORMAL = 0;
private static final int TYPE_COUNT = 2;
private AlphabetIndexer indexer;
private int[] usedSectionNumbers;
private Map<Integer, Integer> sectionToOffset;
private Map<Integer, Integer> sectionToPosition;
protected ImageLoader mImageLoader = new ImageLoader( MyApp.Instance() );
public RecipeListViewAdapter( Context context,
int layout,
Cursor c,
String[] from,
int[] to )
{
super(context, layout, c, from, to);
mContext = context;
mCursor = c;
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
indexer = new AlphabetIndexer(c, c.getColumnIndexOrThrow("NAME"), "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
sectionToPosition = new TreeMap<Integer, Integer>();
sectionToOffset = new HashMap<Integer, Integer>();
final int count = super.getCount();
int i;
for( i = count - 1 ; i >= 0; i-- )
{
sectionToPosition.put(indexer.getSectionForPosition(i), i);
}
i = 0;
usedSectionNumbers = new int[sectionToPosition.keySet().size()];
for( Integer section : sectionToPosition.keySet() )
{
sectionToOffset.put(section, i);
usedSectionNumbers[i] = section;
i++;
}
for(Integer section: sectionToPosition.keySet())
{
sectionToPosition.put(section, sectionToPosition.get(section) + sectionToOffset.get(section));
}
}
@Override
public int getCount()
{
if( super.getCount() != 0 )
{
return super.getCount() + usedSectionNumbers.length;
}
return 0;
}
@Override
public Object getItem(int position)
{
if (getItemViewType(position) == TYPE_NORMAL) //we define this function later
{
return super.getItem( GetItemPosition( position ) );
}
return null;
}
public int GetItemPosition( final int position )
{
return position - sectionToOffset.get(getSectionForPosition(position)) - 1;
}
public int getPositionForSection(int section) {
if (! sectionToOffset.containsKey(section)){
int i = 0;
int maxLength = usedSectionNumbers.length;
while (i < maxLength && section > usedSectionNumbers[i]){
i++;
}
if (i == maxLength) return getCount();
return indexer.getPositionForSection(usedSectionNumbers[i]) + sectionToOffset.get(usedSectionNumbers[i]);
}
return indexer.getPositionForSection(section) + sectionToOffset.get(section);
}
public int getSectionForPosition(int position) {
int i = 0;
int maxLength = usedSectionNumbers.length;
while (i < maxLength && position >= sectionToPosition.get(usedSectionNumbers[i])){
i++;
}
return usedSectionNumbers[i-1];
}
public Object[] getSections() {
return indexer.getSections();
}
//nothing much to this: headers have positions that the sectionIndexer manages.
@Override
public int getItemViewType(int position) {
if (position == getPositionForSection(getSectionForPosition(position))){
return TYPE_HEADER;
} return TYPE_NORMAL;
}
@Override
public int getViewTypeCount() {
return TYPE_COUNT;
}
@Override
public View getView( int position,
View convertView,
ViewGroup parent )
{
final int type = getItemViewType(position);
if (type == TYPE_HEADER)
{
if (convertView == null)
{
convertView = mInflater.inflate(R.layout.header, parent, false);
}
((TextView)convertView.findViewById(R.id.header)).setText((String)getSections()[getSectionForPosition(position)]);
return convertView;
}
else
{
ViewHolder holder = new ViewHolder();
if (convertView == null)
{
convertView = mInflater.inflate(R.layout.recipes_list_view_entry, null);
holder.name = (TextView) convertView.findViewById( R.id.name_entry );
holder.author = (TextView) convertView.findViewById( R.id.username_entry );
holder.ratingBar = (RatingBar) convertView.findViewById( R.id.list_RatingBarId );
holder.userRatingBar = (RatingBar) convertView.findViewById( R.id.list_userRatingBarId );
holder.diffculty = (ImageView) convertView.findViewById( R.id.list_DifficultyImageViewId );
holder.preparationTime = (ImageView) convertView.findViewById( R.id.list_TimeImageViewId );
holder.recipePic = new DisplayableImageView( (ImageView) convertView.findViewById( R.id.list_RecipeImageViewId ) );
holder.name.setTypeface( MyApp.Fonts.ARIAL );
holder.name.setTextSize( MyApp.Fonts.RUNNING_TEXT_SIZE );
holder.name.setTextColor( Color.BLACK );
}
else
{
holder = (ViewHolder) convertView.getTag();
}
if( super.getItem( GetItemPosition(position) ) != null )
{
// Check if single
if( getCount() == position+1 && position == 1 )
{
convertView.setBackgroundResource( R.drawable.list_single );
}
else if( getItemViewType(position-1) == TYPE_HEADER )
{
// Check if single item in the middle of the list
if( getItemViewType(position+1) == TYPE_HEADER )
{
convertView.setBackgroundResource( R.drawable.list_single );
}
else if( position == getCount() - 1 )
{
convertView.setBackgroundResource( R.drawable.list_single );
}
else
{
convertView.setBackgroundResource( R.drawable.list_up );
}
}
else
{
// Middle or bottom
convertView.setBackgroundResource( R.drawable.list_middle );
//If not last
if( getCount() != position + 1 )
{
// Check if middle or down
if( getItemViewType(position+1) == TYPE_HEADER )
{
convertView.setBackgroundResource( R.drawable.list_down );
}
else
{
convertView.setBackgroundResource( R.drawable.list_middle );
}
}
else
{
// If it is last - use list_down
convertView.setBackgroundResource( R.drawable.list_down );
}
}
FillRecipeDataToHolder( GetItemPosition(position), holder );
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
return convertView;
}
}
//these two methods just disable the headers
@Override
public boolean areAllItemsEnabled() {
return false;
}
@Override
public boolean isEnabled(int position) {
if (getItemViewType(position) == TYPE_HEADER){
return false;
}
return true;
}
protected abstract void FillRecipeDataToHolder(int position, ViewHolder holder);
static class ViewHolder
{
TextView separator;
DisplayableImageView recipePic;
TextView name;
TextView author;
RatingBar ratingBar;
RatingBar userRatingBar;
ImageView diffculty;
ImageView preparationTime;
TextView serveCount;
}
}