我正在开发一个Android 3.1应用程序。
我有我的自定义阵列适配器。我想在列表视图中显示名称列表。
这些名称是可以下载并保存在本地的表单。当用户下载并保存一个或多个时,我调用updateFormsNotDownloaded()
。但是当我这样做时,我得到了一个IndexOutOfBoundsException。我认为这个问题是因为我打电话给notifyDataSetChanged()
.
看看我的代码:
public class FormAdapter extends ArrayAdapter<Form>
{
private Context context;
private int layoutResourceId;
private List<Form> forms;
private ArrayList<Integer> checkedItemsPosition;
private Button downloadButton;
public ArrayList<Integer> getCheckedItemsPosition()
{
return checkedItemsPosition;
}
public String[] getSelectedFormsId()
{
String[] ids = new String[checkedItemsPosition.size()];
int i = 0;
for(Integer pos : checkedItemsPosition)
{
Form f = forms.get(pos.intValue());
ids[i] = f.FormId;
i++;
}
return ids;
}
/**
* Called when selected forms has been downloaded and save it locally correctly.
*/
public void updateFormsNotDownloaded()
{
ArrayList<Form> copyForms = new ArrayList<Form>();
for (int i = 0; i < forms.size(); i++)
{
if (!checkedItemsPosition.contains(new Integer(i)))
copyForms.add(forms.get(i));
}
forms = copyForms;
checkedItemsPosition.clear();
notifyDataSetChanged();
}
public FormAdapter(Context context, int textViewResourceId,
List<Form> objects, Button downloadButton)
{
super(context, textViewResourceId, objects);
this.context = context;
this.layoutResourceId = textViewResourceId;
this.forms = objects;
this.checkedItemsPosition = new ArrayList<Integer>();
this.downloadButton = downloadButton;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent)
{
View row = convertView;
if (row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
}
Form f = forms.get(position);
if (f != null)
{
CheckBox checkBox = (CheckBox)row.findViewById(R.id.itemCheckBox);
if (checkBox != null)
{
checkBox.setText(f.Name);
checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked)
{
//Form f = forms.get(position);
if (isChecked)
{
//checkedItems.add(f.FormId);
checkedItemsPosition.add(new Integer(position));
}
else
{
//checkedItems.remove(checkedItems.indexOf(f.FormId));
checkedItemsPosition.remove(checkedItemsPosition.indexOf(new Integer(position)));
}
downloadButton.setEnabled(checkedItemsPosition.size() > 0);
}
});
}
}
return row;
}
}
我在表格上有三个项目,但我删除了其中一个。
为什么我会收到该异常?
这是异常日志:
java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at es.viacognita.adapters.FormAdapter.getView(FormAdapter.java:89)
at android.widget.AbsListView.obtainView(AbsListView.java:1949)
at android.widget.ListView.makeAndAddView(ListView.java:1756)
at android.widget.ListView.fillDown(ListView.java:656)
at android.widget.ListView.fillSpecific(ListView.java:1314)
at android.widget.ListView.layoutChildren(ListView.java:1587)
at android.widget.AbsListView.onLayout(AbsListView.java:1800)
at android.view.View.layout(View.java:9581)
at android.view.ViewGroup.layout(ViewGroup.java:3877)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1542)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1403)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1314)
at android.view.View.layout(View.java:9581)
at android.view.ViewGroup.layout(ViewGroup.java:3877)
at android.widget.FrameLayout.onLayout(FrameLayout.java:400)
at android.view.View.layout(View.java:9581)
at android.view.ViewGroup.layout(ViewGroup.java:3877)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1542)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1403)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1314)
at android.view.View.layout(View.java:9581)
at android.view.ViewGroup.layout(ViewGroup.java:3877)
at android.widget.FrameLayout.onLayout(FrameLayout.java:400)
at android.view.View.layout(View.java:9581)
at android.view.ViewGroup.layout(ViewGroup.java:3877)
at android.view.ViewRoot.performTraversals(ViewRoot.java:1253)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2003)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4025)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
Override getCount()。并返回其中的值 forms.size()。
就我而言,舒巴尤的回答是不够的。 getCount 和 getItem 必须同步并使用相同的列表对象。如果阵列适配器必须使用内部项目列表,则需要覆盖这两个项目。
public class MyArrayAdapter extends ArrayAdapter<MyItemType> {
private final List<MyItemType> items;
public MyArrayAdapter(final Context _context, final int _resource, final List<MyItemType> _items) {
super(_context, _resource, _items);
this.items = _items;
}
// IMPORTANT: either override both getCount and getItem or none as they have to access the same list
@Override
public int getCount() {
return this.items.size();
};
@Override
public Site getItem(final int position) {
return this.items.get(position);
}
...
位置是从 1 开始的,而数组索引是从零开始的。
所以改变这一行:
if (!checkedItemsPosition.contains(new Integer(i)))
copyForms.add(forms.get(i - 1));
您正在使用两个Lists
及其索引 - 但这些列表绝不同步(它们可以单独更改而无需检查其他列表)。
为什么不使用ArrayList<Form> checkForms
和ArrayList<Form> uncheckedForms
,然后您可以从uncheckedForms
中删除对表单的引用并将其添加到checkedForms
这将使List
保持同步。
当您需要获取所有表单时,您可以简单地返回两个ArrayList
的并集。
还没有人回答为什么他会得到例外。因此,即使他的问题很老了,我也会在这里提供我的答案。
您收到异常的原因是,当您更新"forms"时,您会创建一个新的数组对象(因此是一个新的引用)并更改表单对它的引用,而 ArrayAdapter 维护自己的数组对象 mObjects,构造函数将您提供的数组对象(对象)的引用复制到该对象。如果你查看它的源代码,你可以看到这一点(好在它是开源的)。
要真正解决这个问题,您应该使用继承的函数 add(...)、addAll(...) 等来更新数组。或者只是扩展基本适配器并制作自己的实现。