Search code examples
androidsqliteandroid-cursoradapter

Initialize SQLite Cursor before accessing data from it


I am trying to insert data into a SQLite DB once a notification is received via FCM. For debugging purpose I am also inserting a dummy data into my DB when SHow Token is clicked on the HomeScreen activity.

However am getting

"I am getting "Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it."

Link to my code: - GitHub

Can someone please go through my code and let me know where I am going wrong.

Note - I added below in HomeScreen.java,MyFirebaseMessagingService.java and NotificationDetails.java

private SQLiteDB dbHelper = new SQLiteDB(this);
since the suggested
private SQLiteDB dbHelper;
did not work for me

When I used above I kept on getting Nullpointer exception, so I figured since the SQLiteDB class constructor is accepting a context, so let me pass one, post which I did not get NullPointer Exception.

Now I did this without being fully aware of the concept on context which I have been trying to wrap my head around, but since am an extreme noob to android I am not able to grasp it just yet. I suspect it might have something to do with the context I am passing.

Can someone please help me here with detailed instructions on how to fix this issue, I have been through many other threads on this but was not able to fix hence after 5 hrs of going through multiple SO questions, I am posting this one.

Thanks in advance to everyone in the community for the help. :)

Edit

Upon suggestion by admins, I am including below snippet of my code.

Where I am calling the cursor

   dbHelper.insertNotification("This is a notification");
                //Check if the message contains data
                Cursor rs = dbHelper.getAllNotifications();
                rs.moveToFirst();
                token_text.setText("Token: " +rs.getString((rs.getColumnIndex("NOTIFICATION_DETAILS"))));

Insert Notification Function in SQLiteDB.java

public boolean insertNotification(String notification){
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues contentValues = new ContentValues();
    contentValues.put(NOTIFICATION_DETAILS,notification);
    db.insert(NOTIFICATION_TABLE_NAME,null,contentValues);
    return true;
}  

getAllNotifications function

public Cursor getAllNotifications() {
    SQLiteDatabase db = this.getWritableDatabase();
    Cursor res =  db.rawQuery( "SELECT * FROM " + NOTIFICATION_TABLE_NAME, null );
    return res;
}

Solution

  • Couldn't read row 0, col -1 from CursorWindow.

    Is saying that you are attempting to get the column at offset -1 from row 0 (the first row). So you have provided an invalid offset (it cannot be an offset of -1, the offset must be 0 or greater and the maximum value will be 1 less than the number of columns in the Cursor).

    The most likely cause, is that Cursor method getColumnIndex(the_column_name_as_a_string) will return -1 when the column passed to the method cannot be found in the Cursor. Noting that due to a bug column name is case sensitive.

    As such your issue is that the Cursor does not contain a column name NOTIFICATION_DETAILS and as you have used * (all columns) then that column does not exist in the table.

    By the looks of it you should be using the String variable NOTIFICATION_DETAILS so you probably need to use :-

    token_text.setText("Token: " +rs.getString((rs.getColumnIndex(NOTIFICATION_DETAILS)))); //<<<<<<<<<< double quotation marks removed.
    

    Additional

    You should NEVER assume that moveToFirst (or any Cursor move???? method) actually does the move. You should ALWAYS check the returned value. It will be true if the move was successful otherwise it would be false.

    • Again note that the column name passed to the getColumnIndex method is case dependant.

    • As such you should use something like

    :-

           dbHelper.insertNotification("This is a notification");
           //Check if the message contains data
           Cursor rs = dbHelper.getAllNotifications();
           if (rs.moveToFirst()) {
               token_text.setText("Token: " +rs.getString((rs.getColumnIndex(NOTIFICATION_DETAILS))));
           } else {
               ........ code here if anything need to be done if there are no rows extracted 
           }
    

    Addition re comment :-

    Cursor rs = dbHelper.getAllNotifications(); rs.moveToFirst(); do{ for (int i = 0; i < rs.getColumnCount(); i++) { notification_array.add(rs.getString((rs.getColumnIndex(NOTIFICATION_DETAILS)))); } }while (rs.moveToNext());

    using the following is much simpler :-

    Cursor rs = dbHelper.getAllNotifications();
    while (rs.moveToNext()) {
        notification_array.add(rs.getString((rs.getColumnIndex(NOTIFICATION_DETAILS))));
    }