开发者

SectionedAdapter ArrayIndexOutOfBoundsException in AbsListView$RecycleBin.addScrapView() Issue?

I have a Sectioned Adapter that I am using, however I am trying to modify it so that the sections won't appear if they are empty using if (section.adapter.getCount() > 0). I have the following class:

abstract public class SectionedAdapter extends BaseAdapter {

abstract protected View getHeaderView(String caption, int index, View convertView, ViewGroup parent);

private List<Section> sections = new ArrayList<Section>(); 
private static int TYPE_SECTION_HEADER = 0; 

public SectionedAdapter() {
    super(); 
}

public void addSection(String caption, Adapter adapter) { 
    sections.add(new Section(caption, adapter)); 
}

public void clear() {
    sections.clear();
    notifyDataSetInvalidated();
}

@Override
public Object getItem(int position) { 

    for (Section section : this.sections) {
        if (section.adapter.getCount() > 0) {

            if (position == 0) {
                return section;
            }

            int size = section.adapter.getCount() + 1;

            if (position < size) {
                return section.adapter.getItem(position - 1);
            }

            position -= size; 
        }
  开发者_开发百科  } 

    return null; 
}

@Override
public int getCount() {
    int total = 0; 
    for (Section section : this.sections) {
        if (section.adapter.getCount() > 0) {
            // Add Header and Section
            total += section.adapter.getCount() + 1;
        }
    }
    return total;
} 

@Override
public int getViewTypeCount() {
    int total = 1; // Add Header
    for (Section section : this.sections) {
        if (section.adapter.getCount() > 0) {
            // Add Sections
            total += section.adapter.getViewTypeCount();
        }
    } 
    return total;
} 

@Override
public int getItemViewType(int position) { 
    int typeOffset = TYPE_SECTION_HEADER + 1;

    for (Section section : this.sections) {
        if (section.adapter.getCount() > 0) {

            if (position == 0) {
                return TYPE_SECTION_HEADER;
            }

            int size = section.adapter.getCount() + 1;

            if (position < size) {
                return (typeOffset + section.adapter.getItemViewType(position - 1));
            }

            position -= size; 
            typeOffset += section.adapter.getViewTypeCount();
        }
    } 

    return Adapter.IGNORE_ITEM_VIEW_TYPE;
}

@Override
public boolean areAllItemsEnabled() { 
    return false; 
}

@Override
public boolean isEnabled(int position) { 
    return (getItemViewType(position) != TYPE_SECTION_HEADER); 
}

@Override
public View getView(int position, View convertView, ViewGroup parent) { 
    int sectionIndex = 0;
    for (Section section : this.sections) {
        if (section.adapter.getCount() > 0) {

            if (position == 0) {
                return getHeaderView(section.caption, sectionIndex, null, parent);
            }

            int size = section.adapter.getCount() + 1;

            if (position < size) {
                return section.adapter.getView(position - 1, null, parent);
            } 

            position -= size;
            sectionIndex++;
        }
    }
    return null; 
} 

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

class Section { 
    String caption; 
    Adapter adapter; 

    Section(String caption, Adapter adapter) { 
        this.caption = caption; 
        this.adapter = adapter; 
    } 
}

}

This is working however sometimes it will crash with the error ArrayIndexOutOfBoundsException in AbsListView$RecycleBin.addScrapView()

java.lang.ArrayIndexOutOfBoundsException
at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:4186)
at android.widget.ListView.layoutChildren(ListView.java:1572)
at android.widget.AbsListView.onLayout(AbsListView.java:1172)
at android.view.View.layout(View.java:7037)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1249)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1125)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1042)
at android.view.View.layout(View.java:7037)
at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
at android.view.View.layout(View.java:7037)
at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
at android.view.View.layout(View.java:7037)
at android.view.ViewRoot.performTraversals(ViewRoot.java:1054)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1736)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:4701)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)

I know that this error is most likely related to getViewTypeCount() or getItemViewType(int position) but I can't work out where I am going wrong (due to other StackOverflow searches). The exception doesn't occur reliably so I am at a loss to why this would be occurring. Am I missing something here?


If I am not wrong, your aim is not to show section if the section is empty. I don't think the condition you have applied here will give you your desire result.

So remove the conditions that you have put in SectionedAdapter. getHeaderView is abstract method here. But implementation is written in some other class there you have to modify as i did.

SectionedAdapter adapter = new SectionedAdapter() {
        protected View getHeaderView(String caption, int index, View convertView, ViewGroup parent) {
            TextView result = (TextView)convertView;

            if (convertView == null) {
                result=(TextView)getLayoutInflater().inflate(R.layout.header, null);
            }
            if(caption != null) {
                result.setText(caption);
            } else {
                result.setVisibility(View.GONE);
            }

            return(result);
        }
    };

If you don't want to insert any section then in addSelection() method pass null instead of section name.

Please have a look on my modified code. try to run SectionedDemo class

// SectionedDemo class
//----------------------
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class SectionedDemo extends ListActivity {
    private static String[] items={ "lorem", "ipsum", "dolor", "sit", "amet", "consectetuer", "adipiscing", 
                                    "elit", "morbi", "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", 
                                    "etiam", "vel", "erat", "placerat", "ante", "porttitor", "sodales", 
                                    "pellentesque", "augue", "purus"};

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main1);

        adapter.addSection(null, new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items));

        List<String> list = Arrays.asList(items);
        Collections.shuffle(list);
        adapter.addSection(null, new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list));

        list = Arrays.asList(items);
        Collections.shuffle(list);
        adapter.addSection(null, new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list));

        setListAdapter(adapter);
    }

    SectionedAdapter adapter = new SectionedAdapter() {
        protected View getHeaderView(String caption, int index, View convertView, ViewGroup parent) {
            TextView result=(TextView)convertView;

            if (convertView==null) { 
                result=(TextView)getLayoutInflater() .inflate(R.layout.header, null);
            }
            if(caption != null) {
                result.setText(caption);
            } else {
                result.setVisibility(View.GONE);
            }

            return(result);
        }
    };
}

And the following is SectionedAdapter class

//SectionedAdapter class
//-------------------------
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.BaseAdapter;
import java.util.ArrayList;
import java.util.List;

abstract public class SectionedAdapter extends BaseAdapter {
    abstract protected View getHeaderView(String caption, int index, View convertView, ViewGroup parent);

    private List<Section> sections=new ArrayList<Section>();
    private static int TYPE_SECTION_HEADER=0;

    public SectionedAdapter() {
        super();
    }

    public void addSection(String caption, Adapter adapter) {
        sections.add(new Section(caption, adapter));
    }

    public Object getItem(int position) {
        for (Section section : this.sections) {
            if (position==0) {
                return(section);
            }

            int size=section.adapter.getCount()+1;

            if (position<size) {
                return(section.adapter.getItem(position-1));
            }

            position-=size;
        }

        return(null);
    }

    public int getCount() {
        int total = 0;

        for (Section section : this.sections) {
            total += section.adapter.getCount()+1; // add one for header
        }

        return(total);
    }

    public int getViewTypeCount() {
        int total = 1;  // one for the header, plus those from sections

        for (Section section : this.sections) {
            total += section.adapter.getViewTypeCount();
        }

        return(total);
    }

    public int getItemViewType(int position) {
        int typeOffset=TYPE_SECTION_HEADER+1;   // start counting from here

        for (Section section : this.sections) {
            if (position==0) {
                return(TYPE_SECTION_HEADER);
            }

            int size=section.adapter.getCount()+1;

            if (position<size) {
                return(typeOffset+section.adapter.getItemViewType(position-1));
            }

            position-=size;
            typeOffset+=section.adapter.getViewTypeCount();
        }

        return(-1);
    }

    public boolean areAllItemsSelectable() {
        return(false);
    }

    public boolean isEnabled(int position) {
        return(getItemViewType(position)!=TYPE_SECTION_HEADER);
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        int sectionIndex=0;

        for (Section section : this.sections) {

            if (position==0) {
                return(getHeaderView(section.caption, sectionIndex, convertView, parent));
            }

            int size=section.adapter.getCount()+1;

            if (position<size) {
                return(section.adapter.getView(position-1, convertView, parent));
            }

            position-=size;
            sectionIndex++;
        }

        return(null);
    }

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

    class Section {
        String caption;
        Adapter adapter;

        Section(String caption, Adapter adapter) {
            this.caption=caption;
            this.adapter=adapter;
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜