android - ListView 中的 OutOfBoundsException

标签 android listview indexoutofboundsexception

我正在使用 ListView 来呈现类似 GridView 的 Activity 。存在 OutOfBoundsException。这是日志。

03-21 11:47:13.106: E/AndroidRuntime(597): FATAL EXCEPTION: main
03-21 11:47:13.106: E/AndroidRuntime(597): java.lang.IndexOutOfBoundsException: Invalid index 1, size is 1
03-21 11:47:13.106: E/AndroidRuntime(597):  at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
03-21 11:47:13.106: E/AndroidRuntime(597):  at java.util.ArrayList.get(ArrayList.java:304)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.HeaderViewListAdapter.getView(HeaderViewListAdapter.java:225)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.AbsListView.obtainView(AbsListView.java:2022)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.ListView.measureHeightOfChildren(ListView.java:1244)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.ListView.onMeasure(ListView.java:1155)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4698)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.FrameLayout.onMeasure(FrameLayout.java:293)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4698)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1369)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.LinearLayout.measureVertical(LinearLayout.java:660)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.LinearLayout.onMeasure(LinearLayout.java:553)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.RelativeLayout.measureChild(RelativeLayout.java:579)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:392)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4698)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.FrameLayout.onMeasure(FrameLayout.java:293)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4698)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1369)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.LinearLayout.measureVertical(LinearLayout.java:660)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.LinearLayout.onMeasure(LinearLayout.java:553)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4698)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.widget.FrameLayout.onMeasure(FrameLayout.java:293)
03-21 11:47:13.106: E/AndroidRuntime(597):  at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2265)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.View.measure(View.java:12752)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1074)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2462)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.os.Handler.dispatchMessage(Handler.java:99)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.os.Looper.loop(Looper.java:137)
03-21 11:47:13.106: E/AndroidRuntime(597):  at android.app.ActivityThread.main(ActivityThread.java:4486)
03-21 11:47:13.106: E/AndroidRuntime(597):  at java.lang.reflect.Method.invokeNative(Native Method)
03-21 11:47:13.106: E/AndroidRuntime(597):  at java.lang.reflect.Method.invoke(Method.java:511)
03-21 11:47:13.106: E/AndroidRuntime(597):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
03-21 11:47:13.106: E/AndroidRuntime(597):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
03-21 11:47:13.106: E/AndroidRuntime(597):  at dalvik.system.NativeStart.main(Native Method)

我的 ListToGridAdapter 如下:

public class ListToGridAdapter extends BaseAdapter implements OnClickListener, OnLongClickListener {

    /**
     * The wrapper content --> adapter
     */
    private SimpleAdapter mAdapter = null;
    /**
     * The number columns
     */
    private int mColumns = 1;
    /**
     * The real onItemClickListener
     */
    private OnGridItemClickListener mGridListener;
    /**
    * The real onItemLongClickListener
    */
    private OnGridItemLongClickListener mGridLongClickListener;

    /**
     * The Context Object
     */
    private Context mContext;

    private int sidebarPixals = 0;
    private int sideBlankPixals = 0;

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if (mColumns == 1) {
            View child = mAdapter.getView(position, convertView, parent);
            setOnItemClickListenerIfNeed(child, position, position);
            setOnItemLongClickListenerIfNeed(child, position, position);
            // no need
            return child;
        }

        return bindGridView(position, convertView, parent);
    }

    protected View bindGridView(int position, View convertView, ViewGroup parent) {
        ViewGroup root = null;
        if (convertView == null || !(convertView instanceof ViewGroup)) {
            root = createRoot();
            root.setClickable(false);
            root.setFocusable(false);
        } else {
            root = (ViewGroup) convertView;
        }
        // columns = 3
        // pos --> real pos
        // 0 --> 0 1 2
        // 1 --> 3 4 5
        // 2 --> 6 7 8
        // so do this
        return bindView(root, position);
    }

    protected ViewGroup bindView(ViewGroup root, int pos) {

        final int count = mAdapter.getCount();
        final int childCount = root.getChildCount();

        for (int i = 0; i < mColumns; i++) {
            // real position
            int index = mColumns * pos + i;

            // 不足一行时,直接返回现有状态
            if (index == count) {
                // fix bug : root是有可能是系统缓存的root,这里直接返回root将导致如果此行数量
                // 不够columns,就会使用缓存的root里的child,为了避免这个问题,必须
                // 将缓存的child移除。
                removeCacheChild(root, index);
                break;
            } else if (index > count) {
                throw new UnknownError("unknowError");
            }

            View child = mAdapter.getView(index, root.getChildAt(i), root);

            setOnItemLongClickListenerIfNeed(child, pos, index);
            setOnItemClickListenerIfNeed(child, pos, index);

            if (childCount == mColumns) {
                // root已经包含了Item,就没有必要继续添加了。
                continue;
            } else {
                if (i == 0 && childCount != 0) {
                    // 如果root已经包含item,但是并不全,这里就移除重新添加
                    // FIXME 也许还有更好的方案
                    root.removeAllViews();
                }
                LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                        // LinearLayout.LayoutParams.WRAP_CONTENT,
                        (mContext.getResources().getDisplayMetrics().widthPixels - sidebarPixals - sideBlankPixals)
                                / mColumns,
                        LinearLayout.LayoutParams.WRAP_CONTENT);
                child.setFocusable(true);
                child.setClickable(true);
                if (child instanceof ViewGroup) {
                    ((ViewGroup) child)
                            .setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
                }
                root.addView(child, lp);
            }
        }
        return root;
    }

    /**
     * remove child view in cache of root
     */
    private void removeCacheChild(ViewGroup root, int index) {
        int realColumns = (index - 1) % mColumns;
        int moveCount = (mColumns - 1) - realColumns;

        for (int i = 0; i < moveCount; i++) {
            final View child = root.getChildAt((mColumns - 1 - i));
            if (child != null) {
                root.removeView(child);
            }
        }
    }

    /**
     * create root for item of ListView
     */
    protected ViewGroup createRoot() {
        LinearLayout root = new LinearLayout(mContext);
        root.setOrientation(LinearLayout.HORIZONTAL);
        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
                LayoutParams.WRAP_CONTENT);
        root.setLayoutParams(lp);
        return root;
    }

    private boolean setOnItemClickListenerIfNeed(View child, int pos,
            int realPos) {
        if (mGridListener == null) {
            return false;
        }
        child.setOnClickListener(this);
        child.setTag(R.id.pos, pos);
        child.setTag(R.id.realPos, realPos);
        return true;
    }

    private boolean setOnItemLongClickListenerIfNeed(View child, int pos,
            int realPos) {
        if (mGridLongClickListener == null) {
            return false;
        }
        child.setOnLongClickListener(this);
        child.setTag(R.id.pos, pos);
        child.setTag(R.id.realPos, realPos);
        return true;
    }

    public void setOnItemClickListener(OnGridItemClickListener listener) {
        this.mGridListener = listener;
    }

    public void setOnItemLongClickListener(OnGridItemLongClickListener listener){
        this.mGridLongClickListener = listener;
    }

    public void setNumColumns(int columns) {
        this.mColumns = columns;
    }

    public int getNumColumns() {
        return mColumns;
    }

    public ListToGridAdapter(Context context, SimpleAdapter adapter) {
        this.mContext = context;
        this.mAdapter = adapter;
        int model = YoutubeAPI.getKindleFireModel();

        if (model == 1){
            sideBlankPixals = 10 * 2;
            sidebarPixals = 0;
        } else if (model == 2){
            sideBlankPixals = 10 * 2;
            sidebarPixals = 60;
        } else if (model == 3){
            sideBlankPixals = (int)(10 * 2 * 1.5);
            sidebarPixals = 78;
        } else if (model == 4){
            sideBlankPixals = (int)(10 * 2 * 1.5);
            sidebarPixals = 90;
        } 

    }

    @Override
    public int getCount() {
        int count = (int) Math.ceil(mAdapter.getCount() / (double) mColumns);
        return count;
    }

    @Override
    public Object getItem(int position) {
        return mAdapter.getItem(position);
    }

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

    @Override
    public boolean hasStableIds() {
        return mAdapter.hasStableIds();
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        mAdapter.registerDataSetObserver(observer);
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        mAdapter.unregisterDataSetObserver(observer);
    }

    @Override
    public boolean areAllItemsEnabled() {
        return mAdapter.areAllItemsEnabled();
    }

    @Override
    public boolean isEnabled(int position) {
        return mAdapter.isEnabled(position);
    }

    @Override
    public int getItemViewType(int position) {
        return mAdapter.getItemViewType(position);
    }

    @Override
    public int getViewTypeCount() {
        return mAdapter.getViewTypeCount();
    }

    @Override
    public boolean isEmpty() {
        return mAdapter.isEmpty();
    }

    public ListAdapter getWrappedAdapter() {
        return mAdapter;
    }

    public static interface OnGridItemClickListener {
        public void onItemClick(int pos, int realPos);
    }

    public static interface OnGridItemLongClickListener{
        public void onItemLongClick(int pos, int realPos);
    }

    @Override
    public void onClick(View v) {
        if (mGridListener == null) {
            // no need to feedback
        }
        int pos = (Integer) v.getTag(R.id.pos);
        int realPos = (Integer) v.getTag(R.id.realPos);

        mGridListener.onItemClick(pos, realPos);
    }

    @Override
    public boolean onLongClick(View v) {
        if (mGridLongClickListener == null) {
            // no need to feedback
        }
        int pos = (Integer) v.getTag(R.id.pos);
        int realPos = (Integer) v.getTag(R.id.realPos);

        mGridLongClickListener.onItemLongClick(pos, realPos);
        return true;
    }

}

在 Activity 中,

ListToGridAdapter mAdapter = new ListToGridAdapter(this, mVideoGridviewAdapter);
mAdapter.setNumColumns(3);

pullToRefreshListview.setAdapter(mAdapter);

mVideoGridviewAdapter 是一个简单的适配器。

问题出在哪里?好像是 ListView 的页脚,但我不知道如何修复它。

==== 编辑 =====

在 Activity 中,我添加了一些 AsyncTask 来刷新 ListView 。在 onPostExecute 中,我将一些项目添加到 ListView 中,使 ListView 更长,并将 ListView 的页脚 View 从 View.VISIBLE 更改为 View.INVISIBLE,这重要吗?

最佳答案

我自己想出来的。

当更改包含 ListView 的 fragment 时, ListView 会先清空自己,然后 ListView 在滚动时会记住索引,然后,当重新加载 ListView 时,会发生IndexOutOfBoundsException

所以解决方案是:销毁时重置 ListView 的适配器,代码 fragment 如下

public void onDestroyView() {
    if (listview != null && mVideoGridviewAdapter != null) {
        ListToGridWrapper<GridviewAdapter> mAdapter = new ListToGridWrapper<GridviewAdapter>(getActivity(), mVideoGridviewAdapter);
        mAdapter.setNumColumns(2);
        listview.setAdapter(mAdapter);
    }
    super.onDestroyView();
}

关于android - ListView 中的 OutOfBoundsException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15539188/

相关文章:

java - View 需要 API 级别 17 <TextClock>

java - 如何向现有 apk 文件添加附加功能

java - Android:无法获取要在 ListView 中显示的数据

C# ListView DrawSubitem 字体已更改

java - 线程中的异常 "main"java.lang.ArrayIndexOutOfBoundsException : 5

java - 如何在不使用和额外的特殊字符的情况下初始化 6*5 二维矩阵中的 26 个字符

android - 相当于Android中的plist

android - 如何修复 HelloCardboard 示例的 NDK 构建错误

android - 如何在单击 ListView 中的按钮时取消选中所有列表项

java - 数组索引越界