【问题标题】:swapCursor() causes CursorIndexOutOfBoundsException, behaves abnormallyswapCursor() 导致 CursorIndexOutOfBoundsException,行为异常
【发布时间】:2018-02-11 03:23:36
【问题描述】:

几天前我遇到了这个问题,我正在开发一个程序,其中ListView 通过自定义SimpleCursorAdapter 从数据库中获取数据,我曾经使用listView.setAdapter(adapter) 来更新@987654324 中的数据@每次更改数据时。但这会带来一个问题,每次更新数据时,listView 都会自动滚动到顶部,所以我决定改用swapCursor(),如下所示:

Cursor cursor = database.getData();
    if(listView.getAdapter() == null){
        //Toast.makeText(getApplicationContext(),"null",Toast.LENGTH_SHORT).show();
        adapter = (new CustomSimpleCursorAdapter(this,R.layout.todolist,cursor,new String[] {LIST_TEXT},new int[]{R.id.text}));
        listView.setAdapter(adapter);
    }else {
        Runnable runnable =new Runnable() {
            @Override
            public void run() {
                Cursor finalCs = database.getData();
                todoListAdapter.swapCursor(finalCs);
                todoListAdapter.notifyDataSetChanged();
            }
        };
        runOnUiThread(runnable);
    }

但是每次我尝试将数据添加到数据库并在listView中显示时都会出现错误:

**CursorIndexOutOfBoundsException: Index 12 requested, with a size of 12**

(注意,数据是添加到数据库中的,之前使用listView.setAdapter(adapter)没有发现问题,我尝试删除todoListAdapter.notifyDataSetChanged();,但根本没有帮助。另外,当我尝试删除时数据库中的数据并使用更改更新listView,无论我选择哪一项,它始终是listView中的最后一项(现在的数据实际上已从数据库中正确删除),当我尝试再次添加数据,我现在可以添加与之前删除的数据量相同的数据量(如果我删除了 4 项,那么我只能添加 4 项,否则会出现错误)。无论如何,swapCursor()似乎在我使用它时非常糟糕,我做错了什么吗?或者我需要其他东西才能让swapCursor() 工作?提前致谢!

更新:错误回溯上下文:

 android.database.CursorIndexOutOfBoundsException: Index 13 requested, with a size of 13
                                                                   at android.database.AbstractCursor.checkPosition(AbstractCursor.java:460)
                                                                   at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
                                                                   at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
                                                                   at android.support.v4.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:139)

更新:自定义SimpleCursorAdapter

import android.content.Context;
import android.database.Cursor;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;

import java.util.ArrayList;
public class TodoListAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
private ArrayList<Long> itemChecked = new ArrayList<>();
protected int[] mFrom;
protected int[] mTo;

LayoutInflater inflater;
private int mStringConversionColumn = -1;
private CursorToStringConverter mCursorToStringConverter;
private ViewBinder mViewBinder;
MainActivity main;
String[] mOriginalFrom;

public TodoListAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
    super(context, layout, c, from, to,1);
    this.c = c;
    this.context = context;
    mTo = to;
    mOriginalFrom = from;
    inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public ViewBinder getViewBinder() {
    return mViewBinder;
}

public ArrayList returnSelected(){
    return itemChecked;
}

public interface MyInterface{
    public void foo();
}

public void setViewBinder(ViewBinder viewBinder) {
    mViewBinder = viewBinder;
}

public View getView(final int pos, View inView, ViewGroup parent) {
    c.moveToPosition(pos);
    if (inView == null) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inView = inflater.inflate(R.layout.todolist, null);
    }
    final TextView todoText = (TextView) inView.findViewById(R.id.titleText);
    final CheckBox cBox = (CheckBox) inView.findViewById(R.id.multiSelectionBox); 
    System.out.println(c.getCount());
    newView(context,c,parent);
    bindView(inView,context,c);
    final long id = getItemId(pos);
    cBox.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            CheckBox cb = (CheckBox) v.findViewById(R.id.multiSelectionBox);
            if (cb.isChecked()) {
                if(context.toString().contains("MainActivity")){
                    ((MainActivity)context).addSelectedId(id);
                }else if(context.toString().contains("HistoryActivity")){
                    ((HistoryActivity)context).addSelectedId(id);
                }
                System.out.println("checked " + id);
            } else if (!cb.isChecked()) {
                System.out.println("unchecked " + id);
                if(context.toString().contains("MainActivity")){
                    ((MainActivity)context).removeSelectedId(id);
                }else if(context.toString().contains("HistoryActivity")){
                    ((HistoryActivity)context).removeSelectedId(id);
                }                    
            }
        }
    });
    return inView;
}

}

【问题讨论】:

  • 发布整个回溯 - 或至少最后 4-5 帧
  • 我做到了,尽管我认为这个问题的回溯没有那么有用...
  • 发布 SimpleCursorAdapter 和 swapCursor 代码
  • 好的,所以发布您的自定义SimpleCursorAdapter 代码
  • 例如你是否重写了getCount 方法?

标签: android listview simplecursoradapter android-cursoradapter android-cursor


【解决方案1】:

终于搞定了,只是因为我没有把适配器中的游标改成传入的游标,重写bindView方法并在原代码中添加this.c = cursor,然后在调用getView时, cursor 将是新的光标。那只是我自己犯的一个愚蠢的错误。

特别感谢@pskink 帮助我意识到,我根本不需要覆盖bindViewnewView,但你提到c.moveToPosition() 让我意识到了错误。

【讨论】:

    猜你喜欢
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多