ОШИБКА SQLITE: Не удалось прочитать строку 0, столбец -1 из CursorWindow.Убедитесь, что курсор инициализирован правильно, прежде чем получить доступ к данным из него - PullRequest
0 голосов
/ 16 сентября 2018

Приложение Iam для Android с локальной базой данных. Мне нужно получить рекорд каждого пользователя в отдельности. Я попробовал код ниже, чтобы получить оценку пользователя в Textview

РЕДАКТИРОВАТЬ: СОЗДАТЬ БАЗУ ДАННЫХ

 // Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "Mydatabase.db";

private static final String TABLE_REGISTER= "register";
public static final String KEY_ID = "id";
public static final String KEY_FIRST_NAME = " first_name";
public static final String KEY_LAST_NAME = "last_name";
public static final String KEY_EMAIL_ID="email_id";
public static final String KEY_MOB_NO = "mobile_number";
public static final String KEY_PASSWORD = "password";
public static final String KEY_SCORE="score";



public static final String CREATE_TABLE="CREATE TABLE " + TABLE_REGISTER + "(" + KEY_ID + " INTEGER PRIMARY KEY," + KEY_FIRST_NAME + " TEXT,"+ KEY_LAST_NAME + " TEXT,"+ KEY_EMAIL_ID + " TEXT,"
        + KEY_MOB_NO + " TEXT," + KEY_PASSWORD + " TEXT ," + KEY_SCORE +
         " INTEGER)";

 @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS " + TABLE_REGISTER);
  // Create tables again
    onCreate(db); }

void addregister(RegisterData registerdata)
// code to add the new register
{
    SQLiteDatabase db = this.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put(KEY_FIRST_NAME,registerdata.getfirstName()); // register first Name
    values.put(KEY_lAST_NAME, registerdata. getlastName() ); // register last name
    values.put(KEY_EMAIL_ID, registerdata.getEmailId());//register email id
    values.put(KEY_MOB_NO, registerdata.getMobNo());//register mobile no
    values.put(KEY_PASSWORD, registerdata.getPassword());
    values.put(KEY_SCORE,registerdata.getScore());

    // Inserting Row

    db.insert(TABLE_REGISTER, null, values);

    db.close(); // Closing database connection
}

EDIT:

Приведенный ниже код используется для получения одного рекорда

public int getScoreByUsername(String username){
    int highscore = 0;
    String[] col=new String[]{"MAX ( " + KEY_SCORE + ") AS Max_Score"};
    SQLiteDatabase db = this.getReadableDatabase();

    Cursor cursor=db.query(TABLE_REGISTER,col,
             "email_id=?",new String[]{username},null,null,null,null);
    if(cursor.getCount()<1){
        cursor.close();
        return  0;
    }
    else if(cursor.getCount()>=1 && cursor.moveToFirst()){

        highscore = cursor.getInt(cursor.getColumnIndex(KEY_SCORE));
        cursor.close();

    }
    return highscore;

}

Ниже код, используемый для отображения рекордов в текстовом представлении

MAINACTIVITY

highscorelabel.setText(String.valueOf(db.getScoreByUsername(username)));

Но я получаю java.lang.IllegalStateException Ошибка . Вот мой logcat

Caused by: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
                  at android.database.CursorWindow.nativeGetLong(Native Method)
                  at android.database.CursorWindow.getLong(CursorWindow.java:511)
                  at android.database.CursorWindow.getInt(CursorWindow.java:578)
                  at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:69)
                  at com.example.mathu.loginregister.DataBAseHandler.getScoreByUsername(DataBAseHandler.java:201)
                  at com.example.mathu.loginregister.ResultActivity.onCreate(ResultActivity.java:69)
                  at android.app.Activity.performCreate(Activity.java:6847)
                  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
                  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2677)
                  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2785) 
                  at android.app.ActivityThread.-wrap12(ActivityThread.java) 
                  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1532) 
                  at android.os.Handler.dispatchMessage(Handler.java:102) 
                  at android.os.Looper.loop(Looper.java:163) 
                  at android.app.ActivityThread.main(ActivityThread.java:6342) 
                  at java.lang.reflect.Method.invoke(Native Method) 
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:880) 
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:770) 

1 Ответ

0 голосов
/ 16 сентября 2018

Ваша проблема в том, что вы пытаетесь получить данные из столбца, который не существует в курсоре.

Изменить

highscore = cursor.getInt(cursor.getColumnIndex(KEY_SCORE));

К

highscore = cursor.getInt(cursor.getColumnIndex("Max_Score"));

Аргументация объясняется комментарием: -

Продолжая, метод getScoreByEmail также приведет к та же ошибка.

Причина в том, что курсор имеет только имена столбцов, которые Вы указали, чтобы извлечь.

Курсор не имеет имен столбцов согласно таблицы, используемые в качестве источника (, хотя, например, SELECT * говорит, что все столбцы из таблицы ). Как вы фактически говорите SELECT max(score) AS Max_Score FROM register WHERE email_id=the_value_passed, тогда курсор будет иметь только один столбец и он будет называться Max_Score (следовательно, есть нет оценка столбец и, следовательно, -1 из getColumnIndex).

Дополнительный

P.S. метод может быть упрощен до: -

public int getScoreByUsername(String username){
    int highscore = 0;
    String[] col=new String[]{"MAX ( " + KEY_SCORE + ") AS Max_Score"};
    SQLiteDatabase db = this.getReadableDatabase();

    Cursor cursor=db.query(TABLE_REGISTER,col,
             "email_id=?",new String[]{username},null,null,null,null);
    if(cursor.moveToFirst()) {
        highscore = cursor.getInt(cursor.getColumnIndex("Max_Score"));
    }
    cursor.close();
    return highscore;
}
  • т.е. вам нужно только проверить moveToFirst, если число меньше 1, то moveToFirst вернет false.

Рабочий пример базируется на вашем коде

Ниже приведен рабочий пример использования вашего кода с заполненными пробелами. Результат (хотя на пользователя приходится только 1 строка) показывает, что код работает.

То есть журнал содержит (как положено): -

Mary's High Score is 70000
Fred's High Score is 50000

В MainActivity есть: -

    RegisterData fred = new RegisterData("Fred","Bloggs","fred@bloggs.email","0000 000 000","mypassword",50000);
    RegisterData mary = new RegisterData("Mary","Smith","marysmith@emailcom","0000 000 000","mypassword",60000);
    mary.addScore(10000);

Затем следует (добавляет 2 строки в таблицу регистров): -

    MyDBHlpr.addregister(fred);
    MyDBHlpr.addregister(mary);

После чего следует (чтобы получить высокий балл по EmailId и затем вывести значения в журнал): -: -

    int mary_max_score = MyDBHlpr.getScoreByUsername(mary.getEmailId());
    int fred_max_score = MyDBHlpr.getScoreByUsername(fred.getEmailId());
    Log.d("HIGHSCORES","Mary's High Score is " + String.valueOf(mary_max_score));
    Log.d("HIGHSCORES", "Fred's High Score is " + String.valueOf(fred_max_score));

Полный код: -

MainActivity.java

public class MainActivity extends AppCompatActivity {

    DBHelper MyDBHlpr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyDBHlpr = new DBHelper(this);

        RegisterData fred = new RegisterData("Fred","Bloggs","fred@bloggs.email","0000 000 000","mypassword",50000);
        RegisterData mary = new RegisterData("Mary","Smith","marysmith@emailcom","0000 000 000","mypassword",60000);
        mary.addScore(10000);

        MyDBHlpr.addregister(fred);
        MyDBHlpr.addregister(mary);

        int mary_max_score = MyDBHlpr.getScoreByUsername(mary.getEmailId());
        int fred_max_score = MyDBHlpr.getScoreByUsername(fred.getEmailId());
        Log.d("HIGHSCORES","Mary's High Score is " + String.valueOf(mary_max_score));
        Log.d("HIGHSCORES", "Fred's High Score is " + String.valueOf(fred_max_score));
    }
}

DBHelper.java (примечание содержит код отладки, см. Ниже)

public class DBHelper extends SQLiteOpenHelper {

    // Database Version
    private static final int DATABASE_VERSION = 1;
    // Database Name
    private static final String DATABASE_NAME = "Mydatabase.db";

    private static final String TABLE_REGISTER= "register";
    public static final String KEY_ID = "id";
    public static final String KEY_FIRST_NAME = " first_name";
    public static final String KEY_LAST_NAME = "last_name";
    public static final String KEY_EMAIL_ID="email_id";
    public static final String KEY_MOB_NO = "mobile_number";
    public static final String KEY_PASSWORD = "password";
    public static final String KEY_SCORE="score";



    public static final String CREATE_TABLE="CREATE TABLE " + TABLE_REGISTER + "(" + KEY_ID + " INTEGER PRIMARY KEY," + KEY_FIRST_NAME + " TEXT,"+ KEY_LAST_NAME + " TEXT,"+ KEY_EMAIL_ID + " TEXT,"
            + KEY_MOB_NO + " TEXT," + KEY_PASSWORD + " TEXT ," + KEY_SCORE +
            " INTEGER)";

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.getWritableDatabase();
    }

    @Override
    public synchronized void close() {
        super.close();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_REGISTER);
        // Create tables again
        onCreate(db); }

    void addregister(RegisterData registerdata)
// code to add the new register
    {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(KEY_FIRST_NAME,registerdata.getfirstName()); // register first Name
        values.put(KEY_LAST_NAME, registerdata. getlastName() ); // register last name
        values.put(KEY_EMAIL_ID, registerdata.getEmailId());//register email id
        values.put(KEY_MOB_NO, registerdata.getMobNo());//register mobile no
        values.put(KEY_PASSWORD, registerdata.getPassword());
        values.put(KEY_SCORE,registerdata.getScore());

        // Inserting Row

        db.insert(TABLE_REGISTER, null, values);
        db.close(); // Closing database connection
    }

    public int getScoreByUsername(String username){
        int highscore = 0;
        String[] col=new String[]{"MAX ( " + KEY_SCORE + ") AS Max_Score"};
        SQLiteDatabase db = this.getReadableDatabase();

        Cursor cursor=db.query(TABLE_REGISTER,col,
                "email_id=?",new String[]{username},null,null,null,null);
        //<<<<<<<<<< DEBUG CODE
        Log.d("CURSOR COUNT","There are " + String.valueOf(cursor.getCount()) + " rows in the Cursor.");
        logAllRows();
        //<<<<<<<<<< END OF DEBUG CODE
        if(cursor.moveToFirst()) {
            highscore = cursor.getInt(cursor.getColumnIndex("Max_Score"));
        }
        cursor.close();
        return highscore;
    }

    //<<<<<<<<<< ADDED METHOD TO SHOW ALL DATA IN THE REGISTER TABLE
    public void logAllRows() {
        SQLiteDatabase db = this.getWritableDatabase();
        Cursor csr = db.query(TABLE_REGISTER,null,null,null,null,null,null);
        DatabaseUtils.dumpCursor(csr);
        csr.close();
    }
}

RegisterData.java (создан на основе вашего кода, хотя метод addScore был импровизирован)

public class RegisterData {

    private String firstName;
    private String lastName;
    private String EmailId;
    private String MobNo;
    private String Password;
    private int Score;

    RegisterData (String firstName,
                  String lastName,
                  String EmailId,
                  String MobNo,
                  String Password, int Score) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.EmailId = EmailId;
        this.MobNo = MobNo;
        this.Password = Password;
        this.Score = Score;
    }

    RegisterData (String firstName,
                  String lastName,
                  String EmailId,
                  String MobNo,
                  String Password) {
        new RegisterData(firstName, lastName, EmailId, MobNo, Password, 0);
    }

    public String getfirstName() {
        return firstName;
    }

    public void setfirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getlastName() {
        return lastName;
    }

    public void setlastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmailId() {
        return EmailId;
    }

    public void setEmailId(String emailId) {
        EmailId = emailId;
    }

    public String getMobNo() {
        return MobNo;
    }

    public void setMobNo(String mobNo) {
        MobNo = mobNo;
    }

    public String getPassword() {
        return Password;
    }

    public void setPassword(String password) {
        Password = password;
    }

    public int getScore() {
        return Score;
    }

    public void setScore(int score) {
        Score = score;
    }

    public void addScore(int score) {
        Score = Score + score;
    }
}

По сути, ваш код, который вы показали, в порядке. Проблема с получением 0 должна быть в другом месте. Возможно, у вас нет строк.

Однако в класс DBHelper был добавлен некоторый код, который вы можете скопировать, что должно по крайней мере разделить проблему на проблему с добавлением данных в таблицу или на проблему с данными в таблице.

В коде дублирования есть 2 части, обе добавляются в метод getScoreByusername .

В первой части выводится количество извлеченных строк, можно ожидать, что оно будет равно 1. Если оно равно 1, а max_score равно 0, то проблема должна заключаться в том, что столбец оценки равен 0, нулю или значению, которое невозможно преобразовать на число (таким образом, 0 используется) методом getInt . Если это 1, то вторая часть должна указывать на проблему.

с использованием приведенного выше примера привело к: -

09-16 10:12:18.618 1535-1535/? D/CURSOR COUNT: There are 1 rows in the Cursor.

Вторая часть извлекает все строки / столбцы из таблицы и использует метод DatabaseUtils dumpCursor для отображения данных в курсоре.

Это, для примера выше (строка для Фреда и строка для Мэри), будет выглядеть так: -

09-16 10:12:18.618 1535-1535/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@5345b12c
09-16 10:12:18.622 1535-1535/? I/System.out: 0 {
       id=1
       first_name=Fred
       last_name=Bloggs
       email_id=fred@bloggs.email
       mobile_number=0000 000 000
       password=mypassword
       score=50000
    }
    1 {
       id=2
       first_name=Mary
       last_name=Smith
       email_id=marysmith@emailcom
       mobile_number=0000 000 000
       password=mypassword
       score=70000
    }
    <<<<<

Как видите, в столбце оценок для Фреда есть 50000, а в столбце оценок для Мэри - 70000.

Если первая отладка показывает, что была выбрана 1 строка, то вполне вероятно, что оценка не будет действительным числом и, следовательно, 0.

Если первая отладка показывает 0, возможно, столбец email_id не соответствует ожидаемому.

...