我正在尝试将我正在开发的 Android 应用程序上的 Room 数据库从版本 2.4.3 更新到 2.5.2,这些是我的 gradle.build 文件中的 Room 依赖项
dependencies {
val room_version = "2.5.2"
implementation("androidx.room:room-runtime:$room_version")
implementation("androidx.room:room-ktx:$room_version")
kapt("androidx.room:room-compiler:$room_version")
}
应用程序编译并构建成功,但不幸的是在运行时,当使用查询时,Room 崩溃并出现 NoSuchFieldError 错误。
FATAL EXCEPTION: Thread-29
Process: my.app, PID: 29657
java.lang.NoSuchFieldError: No instance field mDelegate of type Landroid/database/sqlite/SQLiteStatement; in class Landroidx/sqlite/db/framework/FrameworkSQLiteStatement; or its superclasses (declaration of 'androidx.sqlite.db.framework.FrameworkSQLiteStatement' appears in /data/app/~~8vd8qCDSVAv==/my.app/base.apk)
at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(Unknown Source:0)
at androidx.room.EntityInsertionAdapter.insertAndReturnId(EntityInsertionAdapter.kt:102)
快速查看源代码后,我的代码似乎位于堆栈跟踪行
at androidx.sqlite.db.framework.FrameworkSQLiteStatement.executeInsert(Unknown Source:0)
指向这个类
package androidx.sqlite.db.framework
import android.database.sqlite.SQLiteStatement
import androidx.sqlite.db.SupportSQLiteStatement
/**
* Delegates all calls to a [SQLiteStatement].
*
* @constructor Creates a wrapper around a framework [SQLiteStatement].
*
* @param delegate The SQLiteStatement to delegate calls to.
*/
internal class FrameworkSQLiteStatement(
private val delegate: SQLiteStatement
) : FrameworkSQLiteProgram(
delegate
), SupportSQLiteStatement {
override fun execute() {
delegate.execute()
}
override fun executeUpdateDelete(): Int {
return delegate.executeUpdateDelete()
}
override fun executeInsert(): Long {
return delegate.executeInsert()
}
override fun simpleQueryForLong(): Long {
return delegate.simpleQueryForLong()
}
override fun simpleQueryForString(): String? {
return delegate.simpleQueryForString()
}
}
这是 androidx.sqlite:sqlite-framework 依赖版本 2.3.0 的源代码。
根据堆栈跟踪日志,Room 似乎指向基于“mDelegate”字段的旧版本。
这是 androidx.sqlite:sqlite-framework 版本 2.0.1,其中有一个定义为“mDelegate”的字段。
看起来(如果我错了,请纠正我)Room 库在运行时正在从旧版本的 sqlite 中查找类,或者整个 Room 库及其对 sqlite 的传递依赖项都在运行旧版本在运行时,尽管我在编译时实际拥有的内容。
尝试到处寻找可能导致此问题的原因。什么也没发生。
我观察到的事情:
我目前使用的是 Room 版本 2.4.3,该问题开始出现在版本 2.5.0-beta01 上。我慢慢地从 Android 网站上增加版本号,直到我准确地找到它开始出现的位置。我测试了 2.5.0-beta01 和 2.5.2 之间的每个版本,它们都会导致运行时崩溃。
该问题存在于不同OEM的不同手机中,与特定设备无关。
我运行了 gradle 依赖关系树任务,没有发现任何库使用任何可传递的 room/sqlite 依赖关系!
我尝试过的事情:
我尝试更新所有其他 Android 依赖项,至少是其中的大多数(我的项目有几十个依赖项)。我尝试更新所有 Androidx 和 Kotlin 依赖项,并尝试注释掉大部分第三方依赖项。
我尝试从 kapt() 切换到 ksp() ,然后再切换到 room 编译器依赖项的 commentProcessor() 。没关系。
我尝试通过严格的 gradle.build 文件中的 {} 和 resolutionStrategy{} 块强制 Room 和 sqlite 版本。
configurations.all {
resolutionStrategy {
force("androidx.room:room-runtime:2.5.2")
force("androidx.room:room-ktx:2.5.2")
force("androidx.room:room-compiler:2.5.2")
force("androidx.sqlite:sqlite-framework:2.3.1")
}
}
dependencies {
implementation("androidx.room:room-runtime") {
version {
strictly("2.5.2")
}
}
// etc for the rest of the room and sqlite dependencies
}
由于这个问题,我现在被迫陷入旧版本的 Room(可能会无限期地),并且像 Workmanager 2.8.1 这样隐式/传递依赖于早于 2.5.0 的 Room 版本的库无法更新,因为我还需要用它来更新 Room。
看起来这次崩溃的原因是旧版本的
sentry
库。
我将应用程序的build.gradle
中的哨兵库更新到最后一个并且所有工作正常。
plugins {
...
id "io.sentry.android.gradle" version "3.12.0"
}