无法从数据库中读取值

时间:2014-07-29 16:07:07

标签: java android sqlite

这是我第一次尝试使用Android和SQLite写入/读取数据库。

下面的代码似乎是插入数据(我可以看到行数增加)但是当我尝试调用该值时,会抛出异常

E/CursorWindow﹕ Failed to read row 0, column -1 from a CursorWindow which has 6 rows, 2 columns.

我无法理解为什么以下失败。

  public void Save(String name, String email) {

    _db.execSQL("CREATE TABLE IF NOT EXISTS MailingList (Email VARCHAR, Name VARCHAR);");

    _db.execSQL("INSERT INTO MailingList (Email, Name) VALUES('" + email + "', '" + name + "');");


    ReadDatabase();
    _db.close();

    //_db.deleteAll();
}

private void ReadDatabase() {

    Cursor cursor = _db.rawQuery("SELECT * FROM MailingList", null);

    int i = cursor.getCount();

    ArrayList<String> results = new ArrayList<String>();
    if (cursor != null) {

        if (cursor.moveToFirst()) {
            do {

                String name = cursor.getString(cursor.getColumnIndex("Name")); //ERROR
                String email = cursor.getString(cursor.getColumnIndex("Email"));
                results.add("Name: " + name + ", Email: " + email);
            } while (cursor.moveToNext());
        }
    }
    ListView myList = (ListView) findViewById(R.id.listViewFromDB);
    myList.setAdapter(new ArrayAdapter<String>(this, R.layout.item_layout, results));
}

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.nativeGetString(Native Method)
            at android.database.CursorWindow.getString(CursorWindow.java:435)
            at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51)
            at com.lmsites.dave.lifecrymailinglist.MyActivity.ReadDatabase(MyActivity.java:106)
            at com.lmsites.dave.lifecrymailinglist.MyActivity.Save(MyActivity.java:88)
            at com.lmsites.dave.lifecrymailinglist.MyActivity.SaveClick(MyActivity.java:73)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at android.view.View$1.onClick(View.java:3830)
            at android.view.View.performClick(View.java:4450)
            at android.view.View$PerformClick.run(View.java:18600)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5026)
            at java.lang.reflect.Method.invokeNative(Native Method)

1 个答案:

答案 0 :(得分:0)

E/CursorWindow﹕ Failed to read row 0, column -1 from a CursorWindow which has 6 rows, 2 columns.

此错误表示您尝试获取不存在的列的列索引。当getColumnIndex()无法找到特定列时,会返回-1。我没有在代码中看到任何错误,所以我认为数据库本身可能有问题。

开发时,您必须记住,只有在卸载应用程序或擦除应用程序管理器中的所有数据时才真正删除SQLite数据库。
因此,如果您在某个时候在sql脚本中犯了错误,或者您添加,删除或重命名了某些列,则需要卸载,然后重新安装应用程序以使这些更改在数据库中生效。


这当然是许多应用程序的一个问题,在开发时你会遇到这种情况。但是,只要您的应用程序位于应用程序商店中,人们就会使用它,并且每次更新时都无法让每个人重新安装您的应用程序。这将是荒谬的,人们不会喜欢它,但有一种解决方法。

您需要将版本号传递到SQLiteOpenHelper。每次更改有关数据库的内容时都会增加此版本号,然后当Android注意到数据库版本增加时,将调用onUpgrade()回调来相应地升级数据库!尝试这样的事情:

public class ExampleSQLiteOpenHelper extends SQLiteOpenHelper {

    public ExampleSQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // The create query here always has to be for the most up to 
        // date version of the database
        db.execSQL("CREATE TABLE MailingList (Email VARCHAR, Name VARCHAR, PhoneNumber VARCHAR);");
        db.execSQL("CREATE TABLE SomeTable (_id PRIMARY KEY AUTOINCREMENT, SomeColumn VARCHAR)");
        ...
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        // This will be called when you are starting your app for the first time 
        // after increasing the version number.

        // This loops through all the version between the current version of             
        // the database and the newest version. upgradeTo is called with each 
        // version in between.
        for(int i = oldVersion + 1; i <= newVersion; i++) {
            upgradeTo(db, i);
        }
    }

    private void upgradeTo(SQLiteDatabase db, int version) {

        // With this switch you can execute the upgrade scripts for each version 
        // of the databse
        switch (version) {
            case 2:
                // in this version we added a new column to MailingList so we 
                // use ALTER TABLE to add the new column
                db.execSQL("ALTER TABLE MailingList ADD COLUMN PhoneNumber VARCHAR");
                break;

            case 3:
                // In this version we added a new table
                db.execSQL("CREATE TABLE SomeTable (_id PRIMARY KEY AUTOINCREMENT, SomeColumn VARCHAR)");
                break;

            case 4:
                ...
                break;

            case 5:
                ...
                break;
        }
    }
}

当然,最简单的解决方案是删除所有表并在onUpgrade中重新创建它们,但是数据库中的所有数据都将丢失。如果您不想要,可以使用上面的代码来逐步升级您的数据库!