Java 正在从Android数据库删除项-光标索引超出范围异常

Java 正在从Android数据库删除项-光标索引超出范围异常,java,android,android-listview,android-sqlite,android-cursor,Java,Android,Android Listview,Android Sqlite,Android Cursor,在我的android应用程序中,我试图从数据库中删除一个项目,在列表视图中选择了相应的项目,并从长按创建的上下文菜单中选择了一个项目。listview是从arraylist填充的,arraylist是从数据库中的项创建的 但是,我在尝试删除listview中除第一项以外的任何内容时出错(这实际上是最近添加的项,也是arraylist中的最后一项,因为listview以相反的顺序显示列表中的项)。如果我尝试删除除最新项目以外的项目,则会出现一个错误,android.database.CursorI

在我的android应用程序中,我试图从数据库中删除一个项目,在列表视图中选择了相应的项目,并从长按创建的上下文菜单中选择了一个项目。listview是从arraylist填充的,arraylist是从数据库中的项创建的

但是,我在尝试删除listview中除第一项以外的任何内容时出错(这实际上是最近添加的项,也是arraylist中的最后一项,因为listview以相反的顺序显示列表中的项)。如果我尝试删除除最新项目以外的项目,则会出现一个错误,android.database.CursorIndexOutOfBoundsException:请求索引0,大小为0

在这个错误之后,如果我试图打开包含listview的活动,我也会收到相同的错误,直到我删除应用程序的数据并再次打开它

如果光标为空并且正在移动到下一行,我尝试了在databasehandler deleteGoalFromDb方法中进行检查,但到目前为止没有成功

在上下文菜单中按delete项时调用的方法(它是菜单中唯一的项):

My deleteGoal()方法:

deleteGoalFromDb:

public void deleteGoalFromDb(int id){
        SQLiteDatabase db = this.getWritableDatabase();
        db.delete(TABLE_GOALS, KEY_ID + " = ?", new String[] {id+""});
        db.close();
    }
public Goal readGoalFromDb(int id) { //method to get a goal from the database
        SQLiteDatabase db = this.getWritableDatabase();

        Cursor cursor = db.query(TABLE_GOALS, new String[] { KEY_ID,
                KEY_STROKE, KEY_TIME_HRS, KEY_TIME_MIN, KEY_TIME_SECS, KEY_DISTANCE, KEY_ACHIEVED, KEY_DATE_GOAL }, KEY_ID + "=?",
                new String[] { String.valueOf(id) }, null, null, null, null);
        if (cursor != null)
            cursor.moveToFirst();

        Goal goal = new Goal(cursor.getInt(0), cursor.getString(1), cursor.getInt(2),
                cursor.getInt(3), cursor.getInt(4),
                cursor.getInt(5), Boolean.parseBoolean(cursor.getString(6)), cursor.getString(7));

        cursor.close();
        db.close();
        return goal;

    }
makeGoalsFromDB:

public void makeGoalsFromDB() {
        //looping through the table, get the goals and add them to the goals list
        goalsList = new ArrayList<Goal>(); 
        int goalsNo = db.getGoalsCount();
        for (int i = 1; i <= goalsNo; i++) { 
            goalsList.add(db.readGoalFromDb(i));
        }
    }
使用(int,String,int,int,int,int,int,int,int,boolean,String)创建目标

这是我的错误日志:

08-24 12:29:37.850: E/AndroidRuntime(7897): FATAL EXCEPTION: main
08-24 12:29:37.850: E/AndroidRuntime(7897): Process: com.lyncht.swimtracker, PID: 7897
08-24 12:29:37.850: E/AndroidRuntime(7897): android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.database.AbstractCursor.checkPosition(AbstractCursor.java:426)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:68)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.lyncht.swimtracker.DatabaseHandler.readGoalFromDb(DatabaseHandler.java:128)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.lyncht.swimtracker.ViewGoals.makeGoalsFromDB(ViewGoals.java:76)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.lyncht.swimtracker.ViewGoals.deleteGoal(ViewGoals.java:68)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.lyncht.swimtracker.ViewGoals.onContextItemSelected(ViewGoals.java:61)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.app.Activity.onMenuItemSelected(Activity.java:2620)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback.onMenuItemSelected(PhoneWindow.java:3864)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:741)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:884)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:874)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.android.internal.view.menu.MenuDialogHelper.onClick(MenuDialogHelper.java:167)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:941)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.widget.AdapterView.performItemClick(AdapterView.java:299)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.widget.AbsListView.performItemClick(AbsListView.java:1113)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.widget.AbsListView$PerformClick.run(AbsListView.java:2911)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.widget.AbsListView$3.run(AbsListView.java:3645)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.os.Handler.handleCallback(Handler.java:733)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.os.Handler.dispatchMessage(Handler.java:95)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.os.Looper.loop(Looper.java:136)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at android.app.ActivityThread.main(ActivityThread.java:5001)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at java.lang.reflect.Method.invokeNative(Native Method)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at java.lang.reflect.Method.invoke(Method.java:515)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
08-24 12:29:37.850: E/AndroidRuntime(7897):     at dalvik.system.NativeStart.main(Native Method)

就像Frank N.Stein已经说过的:你需要使用你想要删除的目标的数据库id。因此,在onContextItemSelected中,编写如下内容:

int idToDelete = listView.getItem(position).getGoalId();
deleteGoal(idToDelete);
readGoalFromDb(int-id)

 Goal goal = null;
 if (cursor != null)
       if(cursor.moveToFirst()) // IMPORTANT!, check whether the returned cursor is empty
       {

           goal = new Goal(cursor.getInt(0), cursor.getString(1), cursor.getInt(2),
            cursor.getInt(3), cursor.getInt(4),
            cursor.getInt(5), Boolean.parseBoolean(cursor.getString(6)), cursor.getString(7));
            return goal;
        }
        else {
           //the returned cursor is empty
             Log.v("cursorempty","the cursor was returned empty");
             return null
        }
您检查了
null
,但没有检查光标是否有项目。您只是尝试检索导致
CursorIndexOutOfBoundsException
的值

如果返回的
光标
为空,请采取适当的操作

将您的
makeGoalsFromDB()
修改为:

public void makeGoalsFromDB() {
        //looping through the table, get the goals and add them to the goals list
        goalsList = new ArrayList<Goal>(); 
        int goalsNo = db.getGoalsCount();
        for (int i = 1; i <= goalsNo; i++) { 
            if(null != db.readGoalFromDb(i)) 
            goalsList.add(db.readGoalFromDb(i));
        }
    }
public void makeGoalsFromDB(){
//在表格中循环,获取目标并将其添加到目标列表中
goalsList=newarraylist();
int goalsNo=db.getGoalsCount();

对于(inti=1;i对于其他有相同问题的人,这里是我最后如何解决的。 在我的数据库处理程序类中,我创建了一个新方法,该方法将遍历goals表中的所有项,如果现在找到了该行(已删除)跳过它并增加一个计数器,如果找到该行,则将目标添加到arraylist。如果一行中空行的计数器达到25,则光标停止搜索,并且我将arraylist中的所有空白项删除

通过添加验证以检查光标是否为空,并跳过项目(如果为空),则会停止尝试到达错误项目时出现光标索引错误或空指针异常。通过在Activity中的deleteGoal中使用idGoal值,意味着它将不引用空行

创建目标arraylist的新方法:(在数据库处理程序类内)

新的目标方法:

public void deleteGoal(int id) {
        db.deleteGoalFromDb(id); //deletes the goal from the database
        makeGoalsFromDB(); //refreshes the goalsList
    }
public void deleteGoal(int position) {
        Goal g = goalsList.get(position); //go to goal in goallist
        db.deleteGoalFromDb(g.idGoal); //deletes the goal from the database, using its id stored in the object
        //Below code will refresh the screen
        ListView lview = (ListView) findViewById(R.id.GoalsTable);
        populateList();
        ListViewAdapter adapter = new ListViewAdapter(this, list);
        lview.setAdapter(adapter);
    }

数据库处理程序类中的deleteGoalFromDb方法保持不变。

Wild guess(因为ut是一个常见错误,所以甚至没有阅读代码):您是否使用ListView项位置作为id来删除行?!我使用的是一个从位置计算的值,该值是项的实际id。您永远不应该依赖项位置相对于表id,因为它们没有任何关系,除非您不将实际id存储在项位置。在这种情况下为什么删除最新的项目效果很好?假设您有55行。您删除了第55行(id=54)。然后插入另一个项目(id=55-惊喜!不再是54!)。重新加载ListView时,此项目编号为54…请立即尝试删除最后一行!我应该在何处返回目标对象?由于它是在if语句中创建的,因此我得到错误“目标无法解析为变量”,在同一位置仍有错误,但现在它是“局部变量目标可能尚未初始化”现在填充goalsList时出现空指针异常,您知道如何解决此问题吗?请检查我的编辑,并在执行时检查日志。现在,当再次加载活动时删除项目时,所有目标都已删除
public ArrayList<Goal> readAllGoals(){
        ArrayList<Goal> goalReturnList = new ArrayList<Goal>();
        SQLiteDatabase db = this.getWritableDatabase();
        String selectQuery = "SELECT  * FROM " + TABLE_GOALS; // Query to select all from goals table
        Cursor cursor = db.rawQuery(selectQuery, null);
        int counter = 0;
        int noFalse = 0;
        boolean z = true;

        while(z) { //the loop will check if there is a record or not and skip past blank records
            if(cursor.moveToPosition(counter)&&noFalse<25){ //if it can get to the next position and there has not been 25 missing in a row
                noFalse = 0; //Reset the counter for number of missing in a row
                Goal goal = new Goal(cursor.getInt(0), cursor.getString(1), cursor.getInt(2),
                            cursor.getInt(3), cursor.getInt(4),
                            cursor.getInt(5), Boolean.parseBoolean(cursor.getString(7)), cursor.getString(6)); //Create the goal to add
                goalReturnList.add(goal); //Add it to the list 
            }else if(noFalse>=25){ 
                z = false;
            }else{
                noFalse++; //Add to the number of false in a row
            }
            counter++; //Increment the counter
        } 
        cursor.close();
        db.close();
        for (Goal g: goalReturnList){
            if (g.strokeGoal.equals("")) { //strip blank goals
                goalReturnList.remove(g);
            }
        }
        return goalReturnList;
    }
public boolean onContextItemSelected(MenuItem item) { //what to do when menu item clicked in context menu
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        deleteGoal(info.position);
        return true;

    }
public void deleteGoal(int position) {
        Goal g = goalsList.get(position); //go to goal in goallist
        db.deleteGoalFromDb(g.idGoal); //deletes the goal from the database, using its id stored in the object
        //Below code will refresh the screen
        ListView lview = (ListView) findViewById(R.id.GoalsTable);
        populateList();
        ListViewAdapter adapter = new ListViewAdapter(this, list);
        lview.setAdapter(adapter);
    }