gpt4 book ai didi

android - 将数据插入 SQLite 时出现间歇性 NPE

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:05:00 25 4
gpt4 key购买 nike

当我在 Android 上向我的 SQLite 表中插入值时,我收到 NullPointerException,我不明白为什么。我正在测试 ContentValues 和数据库实例是否为空。

这是插入代码:

public void insertOrIgnore(ContentValues values) {

SQLiteDatabase db = this.dbHelper.getWritableDatabase();

try {

//I added these null value checks to stop NPE, but doesn't help.
if (values != null && db != null) {
db.insertWithOnConflict(TABLE, null, values, SQLiteDatabase.CONFLICT_IGNORE);
}
} catch (SQLiteException e) {

} finally {
if (db != null) {
db.close();
}
}
}

在哪里

public static final String TABLE = "albums";

大多数情况下,此代码会按预期处理添加到数据库中的数据。但是,它有时但很少 会产生以下错误。堆栈跟踪来自 ACRA,我无法确定此错误是在什么情况下发生的。我正在寻找关于为什么会发生这种情况以及条件是什么的指示。我对 SQLite 的了解是初级水平。

java.lang.NullPointerException
at android.database.sqlite.SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:290)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:96)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:2025)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1965)
at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:690)
at android.database.sqlite.SQLiteDatabase.beginTransactionNonExclusive(SQLiteDatabase.java:605)
at android.database.sqlite.SQLiteStatement.acquireAndLock(SQLiteStatement.java:247)
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:112)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1844)
at com.mydomain.myapp.albums.AlbumsData.insertOrIgnore(AlbumsData.java:89)

第 89 行是上面显示的 db.insertWithOnConflict(...) 调用。

我不是在寻找具有完整代码的答案,而是在寻找问题所在的指针和解释,以便我可以开始自己修复它。

编辑:堆栈跟踪显示 NPE 源自 SQLiteStatement 的第 290 行(4.03 版):

 setNativeHandle(mDatabase.mNativeHandle);

所以看起来数据库实例是空的。当我在事务开始时测试为空时,它如何在事务期间变为空?

最佳答案

如此处所述SQLiteDatabase close() function causing NullPointerException when multiple threads

出现错误的原因可能是您在某个时候关闭了数据库。可能在失败的任务尚未完成时同时发生。

我稍微跟踪了一下堆栈跟踪,大致情况如下:

  • AlbumsData.insertOrIgnore(AlbumsData.java:89)
    你打电话insertWithOnConflict ,它构建生成的 sql 字符串 ( "INSERT OR IGNORE INTO..." ),然后将其与来自 ContentValues 的值包装在一起进入 SQLiteStatement .
  • SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1844) - 立即执行结果语句
  • SQLiteStatement.executeInsert(SQLiteStatement.java:112) - 在实际插入发生之前,数据库需要获取锁。
  • SQLiteStatement.acquireAndLock(SQLiteStatement.java:247) - 这里进行了一些检查,据我所知,数据库对象此时不为空。代码决定它必须开始一个事务。据我所知,数据库对象本身当时并未锁定。
  • SQLiteDatabase.beginTransactionNonExclusive(SQLiteDatabase.java:605) - 只是转发
  • SQLiteDatabase.beginTransaction(SQLiteDatabase.java:690) - 经过一些检查(不确定数据库是否必须存在)后,它将尝试执行 execSQL("BEGIN IMMEDIATE;")
  • SQLiteDatabase.execSQL(SQLiteDatabase.java:1965) - 向前
  • SQLiteDatabase.executeSql(SQLiteDatabase.java:2025) - build 另一个 SQLiteStatement来自 "BEGIN IMMEDIATE; .这个应该立即执行
  • SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:96) - 从检查数据库锁开始,这似乎没问题,这里的数据库不应该为空。然后执行该语句,最后再次解锁数据库。
  • SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:290) - 清理了一些东西,但最终因 NPE 而失败,因为数据库是 null .

行号不匹配,因此该代码中可能有供应商修改/添加。

如您所见,代码在实际使用您提供的数据之前就崩溃了。正要去做

BEGIN TRANSACTION IMMEDIATE; -- crash
INSERT INTO table (...) VALUES (...);
-- (end transaction)

在我看来,这使它成为一个框架错误。在那里内部处理的数据库对象不应该是 null在线的某个地方,尤其是当它似乎在堆栈的更上方不为空时。

我还认为另一个隐藏的异常可能是造成这种情况的根本原因。有很多try { /* do stuff */ } finally { /* clean up */ }代码块和 finally即使 try 部分也会被执行部分抛出异常。现在 finally block 可能会导致另一个异常,结果据我所知,原始异常被 finally block 中的新异常所取代。

特别是executeUpdateDelete()就像

try {
acquireAndLock(WRITE);
// actual statement execution
} finally {
releaseAndUnlock();
}

如果此时数据库关闭,acquireAndLocktry 中的任何代码部分可能会失败,这可能会将数据库对象留在 null这导致releaseAndUnlock再次失败。你应该得到相同的堆栈跟踪。

除此之外,不要像 catch (SQLiteException e) { /* empty */ } 这样的空 catch block 。 .如果可能的话用 ACRA 记录它们/你还没有这样做。

关于android - 将数据插入 SQLite 时出现间歇性 NPE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13565575/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com