【问题标题】:Index 0 Requested with a size of 0 Error in SQLITE DB索引 0 请求大小为 0 SQLITE DB 中的错误
【发布时间】:2015-03-16 19:47:32
【问题描述】:

数据库中有数据(准确地说是两行),每行都有信息。

这是来自 DBADAPTER 的代码(重要,不是全部):

// Field Names:
    public static final String KEY_ROWID = "_id";
    public static final String KEY_DEVICE = "device";
    public static final String KEY_TYPE = "type";
    public static final String KEY_DEVID = "devid";

    public static final String[] ALL_KEYS = new String[] {KEY_ROWID, KEY_DEVICE, KEY_TYPE, KEY_DEVID};
    public static final String[] DEVID_KEY = new String[] {KEY_DEVID};

    // Column Numbers for each Field Name:
    public static final int COL_ROWID = 0;
    public static final int COL_DEVICE = 1;
    public static final int COL_TYPE = 2;
    public static final int COL_DEVID = 3;

    // DataBase info:
    public static final String DATABASE_NAME = "dbDevices";
    public static final String DATABASE_TABLE = "mainDevices";
    public static final int DATABASE_VERSION = 10; // The version number must be incremented each time a change to DB structure occurs.

    //SQL statement to create database
    private static final String DATABASE_CREATE_SQL = 
            "CREATE TABLE " + DATABASE_TABLE 
            + " (" + KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
            + KEY_DEVICE + " TEXT NOT NULL, "
            + KEY_TYPE + " TEXT, "
            + KEY_DEVID + " TEXT NOT NULL "
            + ");";

    private final Context context;
    private DatabaseHelper myDBHelper;
    private SQLiteDatabase db;

    // Get a specific row (by devid)
        public String getDevName(String devid) {
            String name;
            String where = KEY_DEVID + " like '%" + devid + "%'";
            Cursor c =  db.query(true, DATABASE_TABLE, ALL_KEYS, 
                            where, null, null, null, null, null);
                c.moveToFirst();
                name = c.getString(COL_DEVICE);
            return name;
        }

这是调用它的代码:

String incomingMessage = " ";
incomingMessage = in.readLine() + System.getProperty("line.separator");
devName = devDB.getDevName(incomingMessage);

我知道这是获取信息,因为它会记录:
03-16 15:39:47.072: V/String(18073): 5122

每当我运行它时,我都会收到错误:

03-16 15:39:47.122: W/System.err(18073): android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
03-16 15:39:47.122: W/System.err(18073):    at android.database.AbstractCursor.checkPosition(AbstractCursor.java:426)
03-16 15:39:47.122: W/System.err(18073):    at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
03-16 15:39:47.132: W/System.err(18073):    at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
03-16 15:39:47.132: W/System.err(18073):    at com.ti.cc3x.android.DBAdapter.getDevName(DBAdapter.java:121)
03-16 15:39:47.132: W/System.err(18073):    at com.ti.cc3x.android.broadcastListener$1.run(broadcastListener.java:112)
03-16 15:39:47.132: W/System.err(18073):    at java.lang.Thread.run(Thread.java:841)

我已尝试检查非空游标。所做的只是什么都不告诉我。我知道有数据我要求它查看我只是不知道为什么它不会显示它。谁能告诉我哪里出错了?谢谢!

【问题讨论】:

  • 发布logcat时,为了便于阅读,请将其放在代码块中。任何类型的堆栈跟踪或其他冗长的错误消息通常也是如此。
  • 另外,我强烈建议您在 Android 上为 SQLite 使用第三方库,除非您是熟练的 DBA 和/或有实际理由不使用库。 Android 的默认实现虽然功能强大,但非常繁琐且容易出现开发人员错误。我制作了一个小型的开源DatabaseManager 类,它简化了GitHub 上的线程和同步。但我真的建议使用 SugarORM、GreenDao 或 ActiveAndroid(还有其他)。
  • 对于一个潜在的解决方案,您将in.readLine() + "\r\n"(\r\n 是行分隔符)传递给getDevName,因此您的查询实际上是针对LIKE '%line_that_i_read\r\n%',所以您不是获取返回的任何行,因此索引 0 不可用。
  • 这行得通。我删除了行分隔符并使用了 Daniel Nugent 提供的代码,它输出了我需要的内容!惊人的!谢谢!

标签: java android sqlite android-cursor


【解决方案1】:

你在使用SQLiteOpenHelper吗?如果是这样,您需要将数据库变量 db 设置为您的数据库尝试像这样读取或写入它之前:

db = this.getWritableDatabase();

...您的新 getDevName(..) 方法应如下所示:

public String getDevName(String devid) {
    db = this.getWritableDatabase();

    String name;
    String where = KEY_DEVID + " like '%" + devid + "%'";
    Cursor c =  db.query(true, DATABASE_TABLE, ALL_KEYS, 
                    where, null, null, null, null, null);
    c.moveToFirst();
    name = c.getString(COL_DEVICE);

    db.close(); // close your db connection when you're done with it

    return name;
}

来自 Android 开发者文档:

public SQLiteDatabase getWritableDatabase() - 第一次调用时,将打开数据库并调用 onCreate(SQLiteDatabase)、onUpgrade(SQLiteDatabase, int, int) 和/或 onOpen(SQLiteDatabase)。 一旦打开成功,数据库就会被缓存,所以每次需要写入数据库时​​都可以调用该方法。 (确保在不再需要数据库时调用 close()。)权限错误或磁盘已满等错误可能会导致此方法失败,但如果问题得到解决,以后的尝试可能会成功。

【讨论】:

    【解决方案2】:

    从@bwegs 扩展the answer 关于对getWritableDatabase() 的调用。

    尝试使用selectionArgs,因为它更干净。检查moveToFirst()的返回值,一定要关闭游标以避免内存泄漏。

     public String getDevName(String devid) {
        db = myDBHelper.getWritableDatabase();  //get db if not done so already, you may have already done this in code not shown
    
        String name = null;
        String where = KEY_DEVID + " like ?";
        String[] selectionArgs =  new String[] {"%"+ devid + "%" };
        Cursor c =  db.query(true, DATABASE_TABLE, ALL_KEYS, 
                        where, selectionArgs , null, null, null, null);
    
        //Only use cursor if moveToFirst() succeeds
        //this will make it so that you don't get the CursorIndexOutOfBoundsException
        if (c.moveToFirst()){
            name = c.getString(COL_DEVICE);
        }
    
        c.close(); //close your cursor to avoid memory leak!
    
        db.close(); //close here if you call getWritableDatabase() in beginning of this function
    
        //This will return null if no results from query
        return name;
    }
    

    【讨论】:

    • 这与 Jakar 关于从incomingMessage 变量中删除行分隔符的评论一起工作(我不记得我为什么首先放在那里)非常感谢!!!
    • 只是一个想法:通常返回 null 对指示错误很有用,但它也可能对 return "error"; 有益,这样您以后就不会受到空指针异常的影响,如果名称获取无论如何打印,然后它是一种无缝的方式来告诉您的用户错误。但是,这当然取决于个人偏好(或公司偏好)和情况。
    • 好点@Jakar。我们通常对字符串进行空值检查,这是我现在工作的标准约定,但了解其他观点是件好事。另外,很好地解决了行分隔符问题!
    • 这个答案正在meta讨论
    猜你喜欢
    • 1970-01-01
    • 2016-02-09
    • 1970-01-01
    • 2013-08-02
    • 2012-05-01
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    相关资源
    最近更新 更多