【问题标题】:Sometimes empty cursor on SQLite query android有时SQLite查询android上的空光标
【发布时间】:2021-09-01 23:14:13
【问题描述】:

我们一直在设置一个 android 应用程序,但在使用 SQLite 时遇到了一个奇怪的错误,其中相同的查询有时会提供结果,有时不会。

运行以下代码时,它可能会返回请求的行,或者 cursor.moveToFirst 可能会返回 false。导致返回空值。

我一直无法弄清楚为什么cursor.moveToFirst() 可能会失败。代码运行相同的语句,名称在同一个数据库上相同。 奇怪的是,它几乎似乎在给出请求的行和什么都不给出之间交替。 此方法是从 ASyncTask 调用的,因此可能会连续调用多个,但从按钮触发的任务不太可能同时调用两次。

最低 android api 级别为 8

connectionInfo 对象是返回信息的包装器。 connectionName 是与当前始终“默认”检索的行关联的名称。 对象 databaseHelper 是 SQLiteOpenHelper 类的扩展。 readFromCursor 函数从光标中读取项目,并正常工作,问题是当cursor.moveToFirst() 返回 false 时它没有被调用。

public ConnectionInfo getConnectionByName(String connectionName) {
    ConnectionInfo info = null;
    SQLiteDatabase db = databaseHelper.getWritableDatabase();
    Cursor cursor = db.rawQuery(STMT_SELECT_BY_NAME , new String[]{connectionName});

    if (cursor != null) {
        if (cursor.moveToFirst()) {
             info = readFromCursor(cursor);
        }
        cursor.close();
    }       

    DBRefcounter.closeDB(db);   

    return info;
}

调用自:

public ConnectionInfo createConnectionInfo(String connectionName, String siteURL, String subsite, String username, String password){


    ConnectionInfo info = getConnectionByName(connectionName);      

    if(info == null){
        SQLiteDatabase db = databaseHelper.getWritableDatabase();


        ContentValues values = new ContentValues();     

        values.put(COLUMN_CONNECTION_NAME, connectionName);
        values.put(COLUMN_SERVER_URL, siteURL);
        values.put(COLUMN_SUBSITE, subsite);
        values.put(COLUMN_USERNAME, username);
        values.put(COLUMN_PASSWORD, password);
        values.put(COLUMN_LAST_ACCESS_TIME, System.currentTimeMillis());            

        long id = db.insert(TABLE_CONNECTION, null, values);

        DBRefcounter.closeDB(db);//clalls db.close and lowers counter   

        if(id >= 0){

            //Build object to return
        }
    }
    else{
        //update the existing object
    }   

    return info;
}

更新:

谁能告诉我 .close() 和 releaseReference 方法之间的区别?根据 api,它们应该是相同的,但它们表现出不同的行为。

【问题讨论】:

  • 这样检查:if(cursor != null && cursor.moveToFirst()){}
  • 确实没有足够的信息来回答。可能是数据更改或查询更改(例如connectionName)参数。
  • 游标对象永远不会为空,永远不会抛出异常,这是最困扰我的。在当前测试用例中,connectionName 参数始终为“默认”。如果您缺少任何信息,请告诉我们,以便我们尝试提供。
  • 这个问题解决了吗?

标签: java android sqlite


【解决方案1】:

这可能是解释:

连续调用失败,因为您没有正确终止第一次调用:

  1. 返回前,需要调用db.close和cusrsor.close()。 db.close 更重要。
  2. 不这样做会导致第二次调用出错,从而导致光标为空。此异常本质上关闭了数据库。因此,第 3 次调用成功。

【讨论】:

  • 这并不能解决问题。听起来确实是错误的合理来源,但是,我们将仔细研究一下,谢谢。
  • 在DB创建语句中添加了引用计数器,所有引用似乎都清理干净了但问题依然存在
  • 你从哪里打这个电话:getConnectionByName(String connectionName)
  • 删除 try-catch 块和 finally 块。它们是无用的,并且是追踪错误的障碍
  • 添加了调用函数并从问题中删除了try/catch
【解决方案2】:

这也是因为泄漏, 此代码停止泄漏并修复光标问题。

 public class DatabaseHelper extends SQLiteOpenHelper { 
    
      private static DatabaseHelper sInstance;
    
      private static final String DATABASE_NAME = "database_name";
      private static final String DATABASE_TABLE = "table_name";
      private static final int DATABASE_VERSION = 1;
    
      public static DatabaseHelper getInstance(Context context) {
    
        // Use the application context, which will ensure that you 
        // don't accidentally leak an Activity's context.
        if (sInstance == null) {
          sInstance = new DatabaseHelper(context.getApplicationContext());
        }
        return sInstance;
      }
    
      /**
       * Constructor should be private to prevent direct instantiation.
       * make call to static factory method "getInstance()" instead.
       */
      private DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
      }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-17
    相关资源
    最近更新 更多