【问题标题】:IndexOutOfBoundsException issue with ArrayAdapter ClassArrayAdapter 类的 IndexOutOfBoundsException 问题
【发布时间】:2015-03-12 23:03:08
【问题描述】:

我试图弄清楚为什么我会收到以下错误。

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 com.modup.adapter.WorkoutCardsAdapter.getItem(WorkoutCardsAdapter.java:75)
        at com.modup.fragment.CreateFragment$1.onPressed(CreateFragment.java:143)
        at com.modup.adapter.WorkoutCardsAdapter$1.onClick(WorkoutCardsAdapter.java:62)
        at android.view.View.performClick(View.java:4442)
        at android.view.View$PerformClick.run(View.java:18473)
        at android.os.Handler.handleCallback(Handler.java:733)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5105)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
        at dalvik.system.NativeStart.main(Native Method)

我看过很多关于这个主题的帖子,但他们似乎都有相同的答案,在实施这些答案之后,问题似乎仍然存在。

我的案例:

我有一个扩展 ArrayAdapter 的类,这个 Adapter 类用于在我的片段中填充 ListView。一切正常,我可以添加视图,我可以删除视图(有点),我可以访问实现的回调。

问题: 似乎当我添加许多视图 3-4+ 并开始删除它们时,我最终会遇到这个异常。

具体案例: 如果我从顶部视图列表项开始,然后往下走,我似乎不会抛出错误,而且有时我也可以从下往上。如果我不按顺序删除视图(有时),似乎会出现错误。

我该如何解决这个问题?我是否错误地覆盖了 getCount() 和 getItem()?

更新:

检查位置时 mCallback.onPress(position);它看起来好像列表中第一项的位置是 0,只要我不尝试删除它下面的任何列表项,它就会保持 0。一旦我删除了它下面的列表项,第一个列表项的位置就会完全不同。

公共类 WorkoutCardsAdapter 扩展 ArrayAdapter {

private LayoutInflater mInflater;
private String[] repArray, setArray, mgArray;
String TAG = WorkoutCardsAdapter.class.getCanonicalName();
Callback mCallback;
List<WorkoutView> mViews;

public WorkoutCardsAdapter(Context context, List<WorkoutView> views, Callback callback) {
    super(context, 0, views);
    mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mCallback = callback;
    this.mViews = views;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder holder;
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.single_workout_layout, parent, false);
        holder = new ViewHolder();
        holder.spinnerReps = (Spinner) convertView.findViewById(R.id.spinnerReps);
        holder.spinnerSets = (Spinner) convertView.findViewById(R.id.spinnerSets);
        holder.spinnerMuscleGroup = (Spinner) convertView.findViewById(R.id.spinnerWorkoutGroup);
        holder.etWorkoutName = (EditText) convertView.findViewById(R.id.etWorkoutName);
        holder.btnRemoveWorkout = (Button) convertView.findViewById(R.id.btnRemoveWorkout);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }
    holder.btnRemoveWorkout.setTag(position);

    mgArray = getContext().getResources().getStringArray(R.array.string_array_muscle_groups);
    TextSpinnerAdapter adapter = new TextSpinnerAdapter(getContext(), R.layout.spinner_text_item, mgArray);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    holder.spinnerMuscleGroup.setAdapter(adapter);

    setArray = getContext().getResources().getStringArray(R.array.string_array_sets);
    TextSpinnerAdapter adapter1 = new TextSpinnerAdapter(getContext(), R.layout.spinner_text_item, setArray);
    adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    holder.spinnerSets.setAdapter(adapter1);

    repArray = getContext().getResources().getStringArray(R.array.string_array_reps);
    TextSpinnerAdapter adapter2 = new TextSpinnerAdapter(getContext(), R.layout.spinner_text_item, repArray);
    adapter2.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    holder.spinnerReps.setAdapter(adapter2);

    holder.btnRemoveWorkout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int position = (Integer) v.getTag();
            mCallback.onPressed(position);
        }
    });

    return convertView;
}

@覆盖 公共 WorkoutView getItem(最终 int 位置){ 返回 mViews.get(位置); }

@Override
public int getCount() {
    return mViews.size();
}

public interface Callback {
    void onPressed(int pos);
}

private static class ViewHolder {
    public Spinner spinnerMuscleGroup;
    public Spinner spinnerSets;
    public Spinner spinnerReps;
    public EditText etWorkoutName;
    public Button btnRemoveWorkout;
}

}

这是带有回调的适配器实现

mWorkoutCardsAdapter = new WorkoutCardsAdapter(getActivity(), mArrayList, new WorkoutCardsAdapter.Callback() {
    @Override
    public void onPressed(int pos) {
            mWorkoutCardsAdapter.remove(mWorkoutCardsAdapter.getItem(pos));
            mWorkoutCardsAdapter.notifyDataSetChanged();
    }
});

如果有帮助,这就是我在按钮按下时添加新视图的方式

    workoutView = new WorkoutView(getActivity());
    mWorkoutCardsAdapter.add(workoutView);
    mWorkoutCardsAdapter.notifyDataSetChanged();

【问题讨论】:

  • 如果你在onPressed方法中设置断点,如果你点击列表中的第一项,pos的值是多少?
  • 位置 = 0,如果我继续删除第一项,它将保持为 0。当我删除它时,我检查了列表中最后一个项目的位置,它也是 0。当我返回删除列表顶部的项目(第一个位置)时,位置将变为 3 或其他数字。

标签: android android-listview android-arrayadapter


【解决方案1】:

我认为问题在于您没有使用相应的 Button 缓存正确的位置,因此被删除的项目被混淆了。您可以将 Button 的标签设置为位置,并从传递给 onClick() 方法的 View 中检索它,以确保从列表中删除正确的标签。

holder.btnRemoveWorkout.setTag(position);
holder.btnRemoveWorkout.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        int position = (Integer) v.getTag();
        mCallback.onPressed(position);
    }
});

【讨论】:

  • 我只是尝试实现这一点,它似乎不起作用,因为位置似乎根据我按下按钮的列表项而改变。我更新了我的问题以反映我的发现。
  • @ItzHoudini 好吧,如果正确实施,这就是应该解决的问题。另外,请记住,当从 ArrayList 中删除一个项目时,其余项目将从 0 重新排序到 size-1。
  • 我刚刚注意到,当我按下与视图对应的 btnRemoveWorkout 按钮时,它总是会删除底部视图。它不会删除与 btnRemoveWorkout 压力相关的视图。此外,如果我更改其中一个视图的值,它会查看其中一些视图中是否还有其他视图也在进行更改(如果我在列表项 1 中设置微调器值,则列表项 3 和 5 将具有相同的值)
  • 确保setTag() 调用出现在if-else 块之后。通常,在 convertView == null 案例中您唯一需要的是 ViewHolder 实例化和初始化,因此您可能还想在 if-else 之后移动一些其他内容。
  • 我刚刚更新了它,如果你想看看。我实际上不确定底部列表项是否总是被删除。我相信,每当我删除一个 list_item 时,在其他列表视图项中设置的任何值都会重置为正常值。我可以在顶部项目上设置微调器值,然后如果我在除所有项目之外的任何其他项目上使用 btnRemoveWorkout,则只需将其重置为该标准。当我添加列表视图项时也会发生这种情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-29
相关资源
最近更新 更多