SQLITE错误:无法从CursorWindow读取行0,col -1。在从游标访问数据之前,请确保已正确初始化游标

时间:2018-09-16 07:31:07

标签: android sqlite android-sqlite

我使用本地数据库将Android应用程序降级。我需要分别获取每个用户的Highscore。我尝试了以下代码以在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
}

编辑:

下面的代码用于获得单个高分

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;

}

下面的代码用来在textview中显示高分

维护性

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

但是我收到 java.lang.IllegalStateException错误。这里是我的日志

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 :(得分:0)

您的问题是,您正在尝试从游标中不存在的列中获取数据。

更改

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

收件人

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

推理由注释解释:-

  

继续, getScoreByEmail 方法也将导致   同样的错误。

     

原因是游标仅具有以下列名称:   您指定要提取。

     

Cursor没有按   用作来源的表格(,例如SELECT *表示从表格中获取所有列)。   当您有效地说SELECT max(score) AS Max_Score FROM register WHERE email_id=the_value_passed时,光标会   仅一个列,该列将被命名为 Max_Score (因此   没有得分列,因此没有getColumnIndex的-1)。

其他

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类中,您可以复制这些代码,这至少应将问题分为将数据添加到表的问题或表中的数据的问题。

dubegging代码分为两部分,都添加到了 getScoreByusername 方法中。

第一部分打印提取的行数,您希望它是1。如果它是1,并且max_score是0,那么问题就必须是score列是0,null或无法转换的值通过 getInt 方法设置为一个数字(因此使用0)。如果为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
    }
    <<<<<

您会看到Fred的得分列为50000,Mary的得分列为70000。

如果第一次调试显示选择了1行,那么分数可能不是有效数字,因此不是0。

如果第一次调试显示0,则可能是email_id列与预期不符。